Merge "Only create DPCs for LocalDisplays & FLAG_OWN_DISPLAY_GROUP" into sc-dev
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java
index bccef53..3a11417 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java
@@ -53,7 +53,7 @@
             "applyPostLayoutPolicy",
             "applySurfaceChanges",
             "AppTransitionReady",
-            "closeSurfaceTransactiom",
+            "closeSurfaceTransaction",
             "openSurfaceTransaction",
             "performLayout",
             "performSurfacePlacement",
@@ -98,6 +98,10 @@
         }
 
         mTraceMarkParser.forAllSlices((key, slices) -> {
+            if (slices.size() < 2) {
+                Log.w(TAG, "No sufficient samples: " + key);
+                return;
+            }
             for (TraceMarkSlice slice : slices) {
                 state.addExtraResult(key, (long) (slice.getDurationInSeconds() * NANOS_PER_S));
             }
diff --git a/apex/appsearch/framework/api/current.txt b/apex/appsearch/framework/api/current.txt
index f6bfaa3..e08d22c 100644
--- a/apex/appsearch/framework/api/current.txt
+++ b/apex/appsearch/framework/api/current.txt
@@ -24,14 +24,6 @@
     method @Deprecated @NonNull public android.app.appsearch.AppSearchManager.SearchContext.Builder setDatabaseName(@NonNull String);
   }
 
-  public interface AppSearchMigrationHelper {
-    method public void queryAndTransform(@NonNull String, @NonNull android.app.appsearch.AppSearchMigrationHelper.Transformer) throws java.lang.Exception;
-  }
-
-  public static interface AppSearchMigrationHelper.Transformer {
-    method @NonNull public android.app.appsearch.GenericDocument transform(int, int, @NonNull android.app.appsearch.GenericDocument) throws java.lang.Exception;
-  }
-
   public final class AppSearchResult<ValueType> {
     method @Nullable public String getErrorMessage();
     method public int getResultCode();
@@ -109,11 +101,6 @@
     method @NonNull public android.app.appsearch.AppSearchSchema.Int64PropertyConfig.Builder setCardinality(int);
   }
 
-  public static interface AppSearchSchema.Migrator {
-    method public default void onDowngrade(int, int, @NonNull android.app.appsearch.AppSearchMigrationHelper) throws java.lang.Exception;
-    method public default void onUpgrade(int, int, @NonNull android.app.appsearch.AppSearchMigrationHelper) throws java.lang.Exception;
-  }
-
   public abstract static class AppSearchSchema.PropertyConfig {
     method public int getCardinality();
     method @NonNull public String getName();
@@ -221,6 +208,13 @@
     method @NonNull public android.app.appsearch.SearchResults search(@NonNull String, @NonNull android.app.appsearch.SearchSpec);
   }
 
+  public abstract class Migrator {
+    ctor public Migrator();
+    ctor public Migrator(int);
+    method @NonNull @WorkerThread public abstract android.app.appsearch.GenericDocument onDowngrade(int, int, @NonNull android.app.appsearch.GenericDocument);
+    method @NonNull @WorkerThread public abstract android.app.appsearch.GenericDocument onUpgrade(int, int, @NonNull android.app.appsearch.GenericDocument);
+  }
+
   public class PackageIdentifier {
     ctor public PackageIdentifier(@NonNull String, @NonNull byte[]);
     method @NonNull public String getPackageName();
@@ -357,7 +351,7 @@
   }
 
   public final class SetSchemaRequest {
-    method @NonNull public java.util.Map<java.lang.String,android.app.appsearch.AppSearchSchema.Migrator> getMigrators();
+    method @NonNull public java.util.Map<java.lang.String,android.app.appsearch.Migrator> getMigrators();
     method @NonNull public java.util.Set<android.app.appsearch.AppSearchSchema> getSchemas();
     method @NonNull public java.util.Set<java.lang.String> getSchemasNotDisplayedBySystem();
     method @Deprecated @NonNull public java.util.Set<java.lang.String> getSchemasNotVisibleToSystemUi();
@@ -371,7 +365,7 @@
     method @NonNull public android.app.appsearch.SetSchemaRequest.Builder addSchemas(@NonNull java.util.Collection<android.app.appsearch.AppSearchSchema>);
     method @NonNull public android.app.appsearch.SetSchemaRequest build();
     method @NonNull public android.app.appsearch.SetSchemaRequest.Builder setForceOverride(boolean);
-    method @NonNull public android.app.appsearch.SetSchemaRequest.Builder setMigrator(@NonNull String, @NonNull android.app.appsearch.AppSearchSchema.Migrator);
+    method @NonNull public android.app.appsearch.SetSchemaRequest.Builder setMigrator(@NonNull String, @NonNull android.app.appsearch.Migrator);
     method @NonNull public android.app.appsearch.SetSchemaRequest.Builder setSchemaTypeDisplayedBySystem(@NonNull String, boolean);
     method @NonNull public android.app.appsearch.SetSchemaRequest.Builder setSchemaTypeVisibilityForPackage(@NonNull String, boolean, @NonNull android.app.appsearch.PackageIdentifier);
     method @Deprecated @NonNull public android.app.appsearch.SetSchemaRequest.Builder setSchemaTypeVisibilityForSystemUi(@NonNull String, boolean);
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
index 486acb4..9ea73a9 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
@@ -114,8 +114,6 @@
      * @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.
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchMigrationHelper.java b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchMigrationHelper.java
deleted file mode 100644
index 37943fc..0000000
--- a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchMigrationHelper.java
+++ /dev/null
@@ -1,65 +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 android.app.appsearch;
-
-import android.annotation.NonNull;
-import android.annotation.SuppressLint;
-
-/**
- * The helper class for {@link AppSearchSchema} migration.
- *
- * <p>It will query and migrate {@link GenericDocument} in given type to a new version.
- */
-public interface AppSearchMigrationHelper {
-
-    /**
-     * Queries all documents that need to be migrated to the different version, and transform
-     * documents to that version by passing them to the provided {@link Transformer}.
-     *
-     * @param schemaType The schema that need be updated and migrated {@link GenericDocument} under
-     *     this type.
-     * @param transformer The {@link Transformer} that will upgrade or downgrade a {@link
-     *     GenericDocument} to new version.
-     * @see Transformer#transform
-     */
-    // Rethrow the Generic Exception thrown from the Transformer.
-    @SuppressLint("GenericException")
-    void queryAndTransform(@NonNull String schemaType, @NonNull Transformer transformer)
-            throws Exception;
-
-    /** The class to migrate {@link GenericDocument} between different version. */
-    interface Transformer {
-
-        /**
-         * Translates a {@link GenericDocument} from a version to a different version.
-         *
-         * <p>If the uri, schema type or namespace is changed via the transform, it will apply to
-         * the new {@link GenericDocument}.
-         *
-         * @param currentVersion The current version of the document's schema.
-         * @param finalVersion The final version that documents need to be migrated to.
-         * @param document The {@link GenericDocument} need to be translated to new version.
-         * @return A {@link GenericDocument} in new version.
-         */
-        @NonNull
-        // This method will be overridden by users, allow them to throw any customer Exceptions.
-        @SuppressLint("GenericException")
-        GenericDocument transform(
-                int currentVersion, int finalVersion, @NonNull GenericDocument document)
-                throws Exception;
-    }
-}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java
index 2cf5271..55f0c80 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java
@@ -20,7 +20,6 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.SuppressLint;
 import android.app.appsearch.exceptions.IllegalSchemaException;
 import android.app.appsearch.util.BundleUtil;
 import android.os.Bundle;
@@ -179,7 +178,7 @@
          * @throws IllegalStateException if the version is negative or the builder has already been
          *     used.
          * @see AppSearchSession#setSchema
-         * @see AppSearchSchema.Migrator
+         * @see Migrator
          * @see SetSchemaRequest.Builder#setMigrator
          */
         @NonNull
@@ -861,43 +860,4 @@
             }
         }
     }
-
-    /**
-     * A migrator class to translate {@link GenericDocument} from different version of {@link
-     * AppSearchSchema}
-     */
-    public interface Migrator {
-
-        /**
-         * Migrates {@link GenericDocument} to a newer version of {@link AppSearchSchema}.
-         *
-         * <p>This methods will be invoked only if the {@link SetSchemaRequest} is setting a higher
-         * version number than the current {@link AppSearchSchema} saved in AppSearch.
-         *
-         * @param currentVersion The current version of the document's schema.
-         * @param targetVersion The final version that documents need to be migrated to.
-         * @param helper The helper class could help to query all documents need to be migrated.
-         */
-        // This method will be overridden by users, allow them to throw any customer Exceptions.
-        @SuppressLint("GenericException")
-        default void onUpgrade(
-                int currentVersion, int targetVersion, @NonNull AppSearchMigrationHelper helper)
-                throws Exception {}
-
-        /**
-         * Migrates {@link GenericDocument} to an older version of {@link AppSearchSchema}.
-         *
-         * <p>The methods will be invoked only if the {@link SetSchemaRequest} is setting a higher
-         * version number than the current {@link AppSearchSchema} saved in AppSearch.
-         *
-         * @param currentVersion The current version of the document's schema.
-         * @param targetVersion The final version that documents need to be migrated to.
-         * @param helper The helper class could help to query all documents need to be migrated.
-         */
-        // This method will be overridden by users, allow them to throw any customer Exceptions.
-        @SuppressLint("GenericException")
-        default void onDowngrade(
-                int currentVersion, int targetVersion, @NonNull AppSearchMigrationHelper helper)
-                throws Exception {}
-    }
 }
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/Migrator.java b/apex/appsearch/framework/java/external/android/app/appsearch/Migrator.java
new file mode 100644
index 0000000..5ae9a41
--- /dev/null
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/Migrator.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appsearch;
+
+import android.annotation.NonNull;
+import android.annotation.WorkerThread;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * A migrator class to translate {@link GenericDocument} from different version of {@link
+ * AppSearchSchema}
+ *
+ * <p>Make non-backwards-compatible changes will delete all stored documents in old schema. You can
+ * save your documents by setting {@link Migrator} via the {@link
+ * SetSchemaRequest.Builder#setMigrator} for each type and target version you want to save.
+ *
+ * <p>{@link #onDowngrade} or {@link #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 #onDowngrade} or {@link #onUpgrade}, all the
+ * setSchema request will be rejected unless the schema changes are backwards-compatible, and stored
+ * documents won't have any observable changes.
+ */
+public abstract class Migrator {
+    private final int mStartVersion;
+
+    /**
+     * Creates a {@link Migrator} will trigger migration for any version less than the final version
+     * in the new schema.
+     */
+    public Migrator() {
+        this(/*startVersion=*/ 0);
+    }
+
+    /**
+     * Creates a {@link Migrator} with a non-negative start version.
+     *
+     * <p>Providing 0 will trigger migration for any version less than the final version in the new
+     * schema.
+     *
+     * @param startVersion The migration will be only triggered for those versions greater or equal
+     *     to the given startVersion.
+     */
+    public Migrator(int startVersion) {
+        Preconditions.checkArgumentNonnegative(startVersion);
+        mStartVersion = startVersion;
+    }
+
+    /**
+     * @return {@code True} if the current version need to be migrated.
+     * @hide
+     */
+    public boolean shouldMigrateToFinalVersion(int currentVersion, int finalVersion) {
+        return currentVersion >= mStartVersion && currentVersion != finalVersion;
+    }
+
+    /**
+     * Migrates {@link GenericDocument} to a newer version of {@link AppSearchSchema}.
+     *
+     * <p>This method will be invoked only if the {@link SetSchemaRequest} is setting a higher
+     * version number than the current {@link AppSearchSchema} saved in AppSearch.
+     *
+     * <p>This method will be invoked on the background worker thread.
+     *
+     * @param currentVersion The current version of the document's schema.
+     * @param targetVersion The final version that documents need to be migrated to.
+     * @param document The {@link GenericDocument} need to be translated to new version.
+     * @return A {@link GenericDocument} in new version.
+     */
+    @WorkerThread
+    @NonNull
+    public abstract GenericDocument onUpgrade(
+            int currentVersion, int targetVersion, @NonNull GenericDocument document);
+
+    /**
+     * Migrates {@link GenericDocument} to an older version of {@link AppSearchSchema}.
+     *
+     * <p>This method will be invoked only if the {@link SetSchemaRequest} is setting a lower
+     * version number than the current {@link AppSearchSchema} saved in AppSearch.
+     *
+     * <p>This method will be invoked on the background worker thread.
+     *
+     * @param currentVersion The current version of the document's schema.
+     * @param targetVersion The final version that documents need to be migrated to.
+     * @param document The {@link GenericDocument} need to be translated to new version.
+     * @return A {@link GenericDocument} in new version.
+     */
+    @WorkerThread
+    @NonNull
+    public abstract GenericDocument onDowngrade(
+            int currentVersion, int targetVersion, @NonNull GenericDocument document);
+}
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 c054063..c1eedcd 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
@@ -63,24 +63,33 @@
  * 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.
+ * <p>Backward incompatible changes can be made by :
+ *
+ * <ul>
+ *   <li>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.
+ *   <li>Add a {@link 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>
  *
  * @see AppSearchSession#setSchema
+ * @see Migrator
  */
 public final class SetSchemaRequest {
     private final Set<AppSearchSchema> mSchemas;
     private final Set<String> mSchemasNotDisplayedBySystem;
     private final Map<String, Set<PackageIdentifier>> mSchemasVisibleToPackages;
-    private final Map<String, AppSearchSchema.Migrator> mMigrators;
+    private final Map<String, Migrator> mMigrators;
     private final boolean mForceOverride;
 
     SetSchemaRequest(
             @NonNull Set<AppSearchSchema> schemas,
             @NonNull Set<String> schemasNotDisplayedBySystem,
             @NonNull Map<String, Set<PackageIdentifier>> schemasVisibleToPackages,
-            @NonNull Map<String, AppSearchSchema.Migrator> migrators,
+            @NonNull Map<String, Migrator> migrators,
             boolean forceOverride) {
         mSchemas = Preconditions.checkNotNull(schemas);
         mSchemasNotDisplayedBySystem = Preconditions.checkNotNull(schemasNotDisplayedBySystem);
@@ -129,9 +138,12 @@
         return copy;
     }
 
-    /** Returns the map of {@link android.app.appsearch.AppSearchSchema.Migrator}. */
+    /**
+     * Returns the map of {@link Migrator}, the key will be the schema type of the {@link Migrator}
+     * associated with.
+     */
     @NonNull
-    public Map<String, AppSearchSchema.Migrator> getMigrators() {
+    public Map<String, Migrator> getMigrators() {
         return Collections.unmodifiableMap(mMigrators);
     }
 
@@ -164,7 +176,7 @@
         private final Set<String> mSchemasNotDisplayedBySystem = new ArraySet<>();
         private final Map<String, Set<PackageIdentifier>> mSchemasVisibleToPackages =
                 new ArrayMap<>();
-        private final Map<String, AppSearchSchema.Migrator> mMigrators = new ArrayMap<>();
+        private final Map<String, Migrator> mMigrators = new ArrayMap<>();
         private boolean mForceOverride = false;
         private boolean mBuilt = false;
 
@@ -295,7 +307,7 @@
         }
 
         /**
-         * Sets the {@link android.app.appsearch.AppSearchSchema.Migrator}.
+         * Sets the {@link Migrator}.
          *
          * @param schemaType The schema type to set migrator on.
          * @param migrator The migrator translate a document from it's old version to a new
@@ -303,8 +315,7 @@
          */
         @NonNull
         @SuppressLint("MissingGetterMatchingBuilder") // Getter return plural objects.
-        public Builder setMigrator(
-                @NonNull String schemaType, @NonNull AppSearchSchema.Migrator migrator) {
+        public Builder setMigrator(@NonNull String schemaType, @NonNull Migrator migrator) {
             Preconditions.checkNotNull(schemaType);
             Preconditions.checkNotNull(migrator);
             mMigrators.put(schemaType, migrator);
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java
index 98cd49b..d63e437 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java
@@ -128,8 +128,8 @@
      * Returns a {@link Set} of schema type whose new definitions set in the {@link
      * AppSearchSession#setSchema} call were incompatible with the pre-existing schema.
      *
-     * <p>If a {@link android.app.appsearch.AppSearchSchema.Migrator} is provided for this type and
-     * the migration is success triggered. The type will also appear in {@link #getMigratedTypes()}.
+     * <p>If a {@link Migrator} is provided for this type and the migration is success triggered.
+     * The type will also appear in {@link #getMigratedTypes()}.
      *
      * @see AppSearchSession#setSchema
      * @see SetSchemaRequest.Builder#setForceOverride
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/util/SchemaMigrationUtil.java b/apex/appsearch/framework/java/external/android/app/appsearch/util/SchemaMigrationUtil.java
new file mode 100644
index 0000000..fae8ad4
--- /dev/null
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/util/SchemaMigrationUtil.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appsearch.util;
+
+import android.annotation.NonNull;
+import android.app.appsearch.AppSearchResult;
+import android.app.appsearch.AppSearchSchema;
+import android.app.appsearch.Migrator;
+import android.app.appsearch.exceptions.AppSearchException;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Utilities for schema migration.
+ *
+ * @hide
+ */
+public final class SchemaMigrationUtil {
+    private static final String TAG = "AppSearchMigrateUtil";
+
+    private SchemaMigrationUtil() {}
+
+    /**
+     * Finds out which incompatible schema type won't be migrated by comparing its current and final
+     * version number.
+     */
+    @NonNull
+    public static Set<String> getUnmigratedIncompatibleTypes(
+            @NonNull Set<String> incompatibleSchemaTypes,
+            @NonNull Map<String, Migrator> migrators,
+            @NonNull Map<String, Integer> currentVersionMap,
+            @NonNull Map<String, Integer> finalVersionMap)
+            throws AppSearchException {
+        Set<String> unmigratedSchemaTypes = new ArraySet<>();
+        for (String unmigratedSchemaType : incompatibleSchemaTypes) {
+            Integer currentVersion = currentVersionMap.get(unmigratedSchemaType);
+            Integer finalVersion = finalVersionMap.get(unmigratedSchemaType);
+            if (currentVersion == null) {
+                // impossible, we have done something wrong.
+                throw new AppSearchException(
+                        AppSearchResult.RESULT_UNKNOWN_ERROR,
+                        "Cannot find the current version number for schema type: "
+                                + unmigratedSchemaType);
+            }
+            if (finalVersion == null) {
+                // The schema doesn't exist in the SetSchemaRequest.
+                unmigratedSchemaTypes.add(unmigratedSchemaType);
+                continue;
+            }
+            // we don't have migrator or won't trigger migration for this schema type.
+            Migrator migrator = migrators.get(unmigratedSchemaType);
+            if (migrator == null
+                    || !migrator.shouldMigrateToFinalVersion(currentVersion, finalVersion)) {
+                unmigratedSchemaTypes.add(unmigratedSchemaType);
+            }
+        }
+        return Collections.unmodifiableSet(unmigratedSchemaTypes);
+    }
+
+    /**
+     * Triggers upgrade or downgrade migration for the given schema type if its version stored in
+     * AppSearch is different with the version in the request.
+     *
+     * @return {@code True} if we trigger the migration for the given type.
+     */
+    public static boolean shouldTriggerMigration(
+            @NonNull String schemaType,
+            @NonNull Migrator migrator,
+            @NonNull Map<String, Integer> currentVersionMap,
+            @NonNull Map<String, Integer> finalVersionMap)
+            throws AppSearchException {
+        Integer currentVersion = currentVersionMap.get(schemaType);
+        Integer finalVersion = finalVersionMap.get(schemaType);
+        if (currentVersion == null) {
+            Log.d(TAG, "The SchemaType: " + schemaType + " not present in AppSearch.");
+            return false;
+        }
+        if (finalVersion == null) {
+            throw new AppSearchException(
+                    AppSearchResult.RESULT_INVALID_ARGUMENT,
+                    "Receive a migrator for schema type : "
+                            + schemaType
+                            + ", but the schema doesn't exist in the request.");
+        }
+        return migrator.shouldMigrateToFinalVersion(currentVersion, finalVersion);
+    }
+
+    /** Builds a Map of SchemaType and its version of given set of {@link AppSearchSchema}. */
+    @NonNull
+    public static Map<String, Integer> buildVersionMap(
+            @NonNull Collection<AppSearchSchema> schemas) {
+        Map<String, Integer> currentVersionMap = new ArrayMap<>(schemas.size());
+        for (AppSearchSchema currentSchema : schemas) {
+            currentVersionMap.put(currentSchema.getSchemaType(), currentSchema.getVersion());
+        }
+        return currentVersionMap;
+    }
+}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
index 27c9ccb..2806974 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -37,6 +37,7 @@
 import android.os.ParcelableException;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
@@ -58,6 +59,7 @@
     private static final String TAG = "AppSearchManagerService";
     private PackageManagerInternal mPackageManagerInternal;
     private ImplInstanceManager mImplInstanceManager;
+    private UserManager mUserManager;
 
     // Cache of unlocked user ids so we don't have to query UserManager service each time. The
     // "locked" suffix refers to the fact that access to the field should be locked; unrelated to
@@ -74,10 +76,11 @@
         publishBinderService(Context.APP_SEARCH_SERVICE, new Stub());
         mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
         mImplInstanceManager = ImplInstanceManager.getInstance(getContext());
+        mUserManager = getContext().getSystemService(UserManager.class);
     }
 
     @Override
-    public void onUserUnlocked(@NonNull TargetUser user) {
+    public void onUserUnlocking(@NonNull TargetUser user) {
         synchronized (mUnlockedUserIdsLocked) {
             mUnlockedUserIdsLocked.add(user.getUserIdentifier());
         }
@@ -193,7 +196,7 @@
                     try {
                         // TODO(b/173451571): reduce burden of binder thread by enqueue request onto
                         // a separate thread.
-                        impl.putDocument(packageName, databaseName, document);
+                        impl.putDocument(packageName, databaseName, document, /*logger=*/ null);
                         resultBuilder.setSuccess(document.getUri(), /*result=*/ null);
                     } catch (Throwable t) {
                         resultBuilder.setResult(document.getUri(), throwableToFailedResult(t));
@@ -509,7 +512,13 @@
 
         private void verifyUserUnlocked(int callingUserId) {
             synchronized (mUnlockedUserIdsLocked) {
-                if (!mUnlockedUserIdsLocked.contains(callingUserId)) {
+                // First, check the local copy.
+                if (mUnlockedUserIdsLocked.contains(callingUserId)) {
+                    return;
+                }
+                // If the local copy says the user is locked, check with UM for the actual state,
+                // since the user might just have been unlocked.
+                if (!mUserManager.isUserUnlockingOrUnlocked(UserHandle.of(callingUserId))) {
                     throw new IllegalStateException(
                             "User " + callingUserId + " is locked or not running.");
                 }
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java b/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java
index 7c92456..ad94a0a 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java
@@ -368,7 +368,8 @@
                     packageAccessibleDocuments.toArray(new GenericDocument[0]));
         }
 
-        mAppSearchImpl.putDocument(PACKAGE_NAME, DATABASE_NAME, visibilityDocument.build());
+        mAppSearchImpl.putDocument(
+                PACKAGE_NAME, DATABASE_NAME, visibilityDocument.build(), /*logger=*/ null);
 
         // Update derived data structures.
         mNotPlatformSurfaceableMap.put(prefix, schemasNotPlatformSurfaceable);
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 e2c211b..5e8760e 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
@@ -17,6 +17,7 @@
 package com.android.server.appsearch.external.localstorage;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.WorkerThread;
 import android.app.appsearch.AppSearchResult;
 import android.app.appsearch.AppSearchSchema;
@@ -29,6 +30,7 @@
 import android.app.appsearch.exceptions.AppSearchException;
 import android.content.Context;
 import android.os.Bundle;
+import android.os.SystemClock;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
@@ -43,6 +45,7 @@
 import com.android.server.appsearch.external.localstorage.converter.SearchSpecToProtoConverter;
 import com.android.server.appsearch.external.localstorage.converter.SetSchemaResponseToProtoConverter;
 import com.android.server.appsearch.external.localstorage.converter.TypePropertyPathToProtoConverter;
+import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
 
 import com.google.android.icing.IcingSearchEngine;
 import com.google.android.icing.proto.DeleteByQueryResultProto;
@@ -449,23 +452,65 @@
     public void putDocument(
             @NonNull String packageName,
             @NonNull String databaseName,
-            @NonNull GenericDocument document)
+            @NonNull GenericDocument document,
+            @Nullable AppSearchLogger logger)
             throws AppSearchException {
+        PutDocumentStats.Builder pStatsBuilder = null;
+        if (logger != null) {
+            pStatsBuilder = new PutDocumentStats.Builder(packageName, databaseName);
+        }
+        long totalStartTimeMillis = SystemClock.elapsedRealtime();
+
         mReadWriteLock.writeLock().lock();
         try {
             throwIfClosedLocked();
 
+            // Generate Document Proto
+            long generateDocumentProtoStartTimeMillis = SystemClock.elapsedRealtime();
             DocumentProto.Builder documentBuilder =
                     GenericDocumentToProtoConverter.toDocumentProto(document).toBuilder();
+            long generateDocumentProtoEndTimeMillis = SystemClock.elapsedRealtime();
+
+            // Rewrite Document Type
+            long rewriteDocumentTypeStartTimeMillis = SystemClock.elapsedRealtime();
             String prefix = createPrefix(packageName, databaseName);
             addPrefixToDocument(documentBuilder, prefix);
+            long rewriteDocumentTypeEndTimeMillis = SystemClock.elapsedRealtime();
 
             PutResultProto putResultProto = mIcingSearchEngineLocked.put(documentBuilder.build());
             addToMap(mNamespaceMapLocked, prefix, documentBuilder.getNamespace());
 
+            // Logging stats
+            if (logger != null) {
+                pStatsBuilder
+                        .getGeneralStatsBuilder()
+                        .setStatusCode(
+                                statusProtoToAppSearchException(putResultProto.getStatus())
+                                        .getResultCode());
+                pStatsBuilder
+                        .setGenerateDocumentProtoLatencyMillis(
+                                (int)
+                                        (generateDocumentProtoEndTimeMillis
+                                                - generateDocumentProtoStartTimeMillis))
+                        .setRewriteDocumentTypesLatencyMillis(
+                                (int)
+                                        (rewriteDocumentTypeEndTimeMillis
+                                                - rewriteDocumentTypeStartTimeMillis));
+                AppSearchLoggerHelper.copyNativeStats(
+                        putResultProto.getPutDocumentStats(), pStatsBuilder);
+            }
+
             checkSuccess(putResultProto.getStatus());
         } finally {
             mReadWriteLock.writeLock().unlock();
+
+            if (logger != null) {
+                long totalEndTimeMillis = SystemClock.elapsedRealtime();
+                pStatsBuilder
+                        .getGeneralStatsBuilder()
+                        .setTotalLatencyMillis((int) (totalEndTimeMillis - totalStartTimeMillis));
+                logger.logStats(pStatsBuilder.build());
+            }
         }
     }
 
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java
new file mode 100644
index 0000000..5680670
--- /dev/null
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.appsearch.external.localstorage;
+
+import android.annotation.NonNull;
+
+import com.android.internal.util.Preconditions;
+import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
+
+import com.google.android.icing.proto.PutDocumentStatsProto;
+
+/**
+ * Class contains helper functions for logging.
+ *
+ * <p>E.g. we need to have helper functions to copy numbers from IcingLib to stats classes.
+ *
+ * @hide
+ */
+public final class AppSearchLoggerHelper {
+    private AppSearchLoggerHelper() {}
+
+    /**
+     * Copies native stats to builder.
+     *
+     * @param fromNativeStats stats copied from
+     * @param toStatsBuilder stats copied to
+     */
+    static void copyNativeStats(
+            @NonNull PutDocumentStatsProto fromNativeStats,
+            @NonNull PutDocumentStats.Builder toStatsBuilder) {
+        Preconditions.checkNotNull(fromNativeStats);
+        Preconditions.checkNotNull(toStatsBuilder);
+        toStatsBuilder
+                .setNativeLatencyMillis(fromNativeStats.getLatencyMs())
+                .setNativeDocumentStoreLatencyMillis(fromNativeStats.getDocumentStoreLatencyMs())
+                .setNativeIndexLatencyMillis(fromNativeStats.getIndexLatencyMs())
+                .setNativeIndexMergeLatencyMillis(fromNativeStats.getIndexMergeLatencyMs())
+                .setNativeDocumentSizeBytes(fromNativeStats.getDocumentSize())
+                .setNativeNumTokensIndexed(
+                        fromNativeStats.getTokenizationStats().getNumTokensIndexed())
+                .setNativeExceededMaxNumTokens(
+                        fromNativeStats.getTokenizationStats().getExceededMaxTokenNum());
+    }
+}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchMigrationHelperImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchMigrationHelperImpl.java
deleted file mode 100644
index 4b8ce6d..0000000
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchMigrationHelperImpl.java
+++ /dev/null
@@ -1,168 +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.appsearch.external.localstorage;
-
-import static android.app.appsearch.AppSearchResult.throwableToFailedResult;
-
-import android.annotation.NonNull;
-import android.app.appsearch.AppSearchBatchResult;
-import android.app.appsearch.AppSearchMigrationHelper;
-import android.app.appsearch.GenericDocument;
-import android.app.appsearch.SearchResultPage;
-import android.app.appsearch.SearchSpec;
-import android.app.appsearch.SetSchemaResponse;
-import android.app.appsearch.exceptions.AppSearchException;
-import android.os.Bundle;
-import android.os.Parcel;
-
-import com.android.internal.util.Preconditions;
-
-import com.google.protobuf.CodedInputStream;
-import com.google.protobuf.CodedOutputStream;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Map;
-
-/**
- * An implementation of {@link AppSearchMigrationHelper} which query document and save post-migrated
- * documents to locally in the app's storage space.
- */
-class AppSearchMigrationHelperImpl implements AppSearchMigrationHelper {
-    private final AppSearchImpl mAppSearchImpl;
-    private final String mPackageName;
-    private final String mDatabaseName;
-    private final File mFile;
-    private final Map<String, Integer> mCurrentVersionMap;
-    private final Map<String, Integer> mFinalVersionMap;
-
-    AppSearchMigrationHelperImpl(
-            @NonNull AppSearchImpl appSearchImpl,
-            @NonNull Map<String, Integer> currentVersionMap,
-            @NonNull Map<String, Integer> finalVersionMap,
-            @NonNull String packageName,
-            @NonNull String databaseName)
-            throws IOException {
-        mAppSearchImpl = Preconditions.checkNotNull(appSearchImpl);
-        mCurrentVersionMap = Preconditions.checkNotNull(currentVersionMap);
-        mFinalVersionMap = Preconditions.checkNotNull(finalVersionMap);
-        mPackageName = Preconditions.checkNotNull(packageName);
-        mDatabaseName = Preconditions.checkNotNull(databaseName);
-        mFile = File.createTempFile(/*prefix=*/ "appsearch", /*suffix=*/ null);
-    }
-
-    @Override
-    public void queryAndTransform(
-            @NonNull String schemaType, @NonNull AppSearchMigrationHelper.Transformer migrator)
-            throws Exception {
-        Preconditions.checkState(mFile.exists(), "Internal temp file does not exist.");
-        int currentVersion = mCurrentVersionMap.get(schemaType);
-        int finalVersion = mFinalVersionMap.get(schemaType);
-        try (FileOutputStream outputStream = new FileOutputStream(mFile)) {
-            // TODO(b/151178558) change the output stream so that we can use it in platform
-            CodedOutputStream codedOutputStream = CodedOutputStream.newInstance(outputStream);
-            SearchResultPage searchResultPage =
-                    mAppSearchImpl.query(
-                            mPackageName,
-                            mDatabaseName,
-                            /*queryExpression=*/ "",
-                            new SearchSpec.Builder()
-                                    .addFilterSchemas(schemaType)
-                                    .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
-                                    .build());
-            while (!searchResultPage.getResults().isEmpty()) {
-                for (int i = 0; i < searchResultPage.getResults().size(); i++) {
-                    GenericDocument newDocument =
-                            migrator.transform(
-                                    currentVersion,
-                                    finalVersion,
-                                    searchResultPage.getResults().get(i).getGenericDocument());
-                    Bundle bundle = newDocument.getBundle();
-                    Parcel parcel = Parcel.obtain();
-                    parcel.writeBundle(bundle);
-                    byte[] serializedMessage = parcel.marshall();
-                    parcel.recycle();
-                    codedOutputStream.writeByteArrayNoTag(serializedMessage);
-                }
-                codedOutputStream.flush();
-                searchResultPage = mAppSearchImpl.getNextPage(searchResultPage.getNextPageToken());
-                outputStream.flush();
-            }
-        }
-    }
-
-    /**
-     * Reads {@link GenericDocument} from the temperate file and saves them to AppSearch.
-     *
-     * <p>This method should be only called once.
-     *
-     * @return the {@link AppSearchBatchResult} for migration documents.
-     */
-    @NonNull
-    public SetSchemaResponse readAndPutDocuments(SetSchemaResponse.Builder responseBuilder)
-            throws IOException, AppSearchException {
-        Preconditions.checkState(mFile.exists(), "Internal temp file does not exist.");
-        try (InputStream inputStream = new FileInputStream(mFile)) {
-            CodedInputStream codedInputStream = CodedInputStream.newInstance(inputStream);
-            while (!codedInputStream.isAtEnd()) {
-                GenericDocument document = readDocumentFromInputStream(codedInputStream);
-                try {
-                    mAppSearchImpl.putDocument(mPackageName, mDatabaseName, document);
-                } catch (Throwable t) {
-                    responseBuilder.addMigrationFailure(
-                            new SetSchemaResponse.MigrationFailure.Builder()
-                                    .setNamespace(document.getNamespace())
-                                    .setSchemaType(document.getSchemaType())
-                                    .setUri(document.getUri())
-                                    .setAppSearchResult(throwableToFailedResult(t))
-                                    .build());
-                }
-            }
-            mAppSearchImpl.persistToDisk();
-            return responseBuilder.build();
-        } finally {
-            mFile.delete();
-        }
-    }
-
-    void deleteTempFile() {
-        mFile.delete();
-    }
-
-    /**
-     * Reads {@link GenericDocument} from given {@link CodedInputStream}.
-     *
-     * @param codedInputStream The codedInputStream to read from
-     * @throws IOException on File operation error.
-     */
-    @NonNull
-    private static GenericDocument readDocumentFromInputStream(
-            @NonNull CodedInputStream codedInputStream) throws IOException {
-        byte[] serializedMessage = codedInputStream.readByteArray();
-
-        Parcel parcel = Parcel.obtain();
-        parcel.unmarshall(serializedMessage, 0, serializedMessage.length);
-        parcel.setDataPosition(0);
-        Bundle bundle = parcel.readBundle();
-        parcel.recycle();
-
-        return new GenericDocument(bundle);
-    }
-}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/CallStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/CallStats.java
index 81a5067..a724f95 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/CallStats.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/CallStats.java
@@ -76,7 +76,7 @@
 
     CallStats(@NonNull Builder builder) {
         Preconditions.checkNotNull(builder);
-        mGeneralStats = Preconditions.checkNotNull(builder.mGeneralStats);
+        mGeneralStats = Preconditions.checkNotNull(builder.mGeneralStatsBuilder).build();
         mCallType = builder.mCallType;
         mEstimatedBinderLatencyMillis = builder.mEstimatedBinderLatencyMillis;
         mNumOperationsSucceeded = builder.mNumOperationsSucceeded;
@@ -132,15 +132,23 @@
 
     /** Builder for {@link CallStats}. */
     public static class Builder {
-        @NonNull final GeneralStats mGeneralStats;
+        @NonNull final GeneralStats.Builder mGeneralStatsBuilder;
         @CallType int mCallType;
         int mEstimatedBinderLatencyMillis;
         int mNumOperationsSucceeded;
         int mNumOperationsFailed;
 
-        /** Builder takes {@link GeneralStats} to hold general stats. */
-        public Builder(@NonNull GeneralStats generalStats) {
-            mGeneralStats = Preconditions.checkNotNull(generalStats);
+        /** Builder takes {@link GeneralStats.Builder}. */
+        public Builder(@NonNull String packageName, @NonNull String database) {
+            Preconditions.checkNotNull(packageName);
+            Preconditions.checkNotNull(database);
+            mGeneralStatsBuilder = new GeneralStats.Builder(packageName, database);
+        }
+
+        /** Returns {@link GeneralStats.Builder}. */
+        @NonNull
+        public GeneralStats.Builder getGeneralStatsBuilder() {
+            return mGeneralStatsBuilder;
         }
 
         /** Sets type of the call. */
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/GeneralStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/GeneralStats.java
index d2a45d5..8ce8eda 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/GeneralStats.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/GeneralStats.java
@@ -82,18 +82,18 @@
     public static class Builder {
         @NonNull final String mPackageName;
         @NonNull final String mDatabase;
-        @AppSearchResult.ResultCode int mStatusCode;
+        @AppSearchResult.ResultCode int mStatusCode = AppSearchResult.RESULT_UNKNOWN_ERROR;
         int mTotalLatencyMillis;
 
         /**
          * Constructor
          *
          * @param packageName name of the package logging stats
-         * @param dataBase name of the database logging stats
+         * @param database name of the database logging stats
          */
-        public Builder(@NonNull String packageName, @NonNull String dataBase) {
+        public Builder(@NonNull String packageName, @NonNull String database) {
             mPackageName = Preconditions.checkNotNull(packageName);
-            mDatabase = Preconditions.checkNotNull(dataBase);
+            mDatabase = Preconditions.checkNotNull(database);
         }
 
         /** Sets status code returned from {@link AppSearchResult#getResultCode()} */
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/PutDocumentStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/PutDocumentStats.java
index b1b643b..c1f6fb1 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/PutDocumentStats.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/PutDocumentStats.java
@@ -54,12 +54,14 @@
     /** Number of tokens added to the index. */
     private final int mNativeNumTokensIndexed;
 
-    /** Number of tokens clipped for exceeding the max number. */
-    private final int mNativeNumTokensClipped;
+    /**
+     * Whether the number of tokens to be indexed exceeded the max number of tokens per document.
+     */
+    private final boolean mNativeExceededMaxNumTokens;
 
     PutDocumentStats(@NonNull Builder builder) {
         Preconditions.checkNotNull(builder);
-        mGeneralStats = Preconditions.checkNotNull(builder.mGeneralStats);
+        mGeneralStats = Preconditions.checkNotNull(builder.mGeneralStatsBuilder).build();
         mGenerateDocumentProtoLatencyMillis = builder.mGenerateDocumentProtoLatencyMillis;
         mRewriteDocumentTypesLatencyMillis = builder.mRewriteDocumentTypesLatencyMillis;
         mNativeLatencyMillis = builder.mNativeLatencyMillis;
@@ -68,7 +70,7 @@
         mNativeIndexMergeLatencyMillis = builder.mNativeIndexMergeLatencyMillis;
         mNativeDocumentSizeBytes = builder.mNativeDocumentSizeBytes;
         mNativeNumTokensIndexed = builder.mNativeNumTokensIndexed;
-        mNativeNumTokensClipped = builder.mNativeNumTokensClipped;
+        mNativeExceededMaxNumTokens = builder.mNativeExceededMaxNumTokens;
     }
 
     /** Returns the {@link GeneralStats} object attached to this instance. */
@@ -117,14 +119,17 @@
         return mNativeNumTokensIndexed;
     }
 
-    /** Returns number of tokens clipped for exceeding the max number. */
-    public int getNativeNumTokensClipped() {
-        return mNativeNumTokensClipped;
+    /**
+     * Returns whether the number of tokens to be indexed exceeded the max number of tokens per
+     * document.
+     */
+    public boolean getNativeExceededMaxNumTokens() {
+        return mNativeExceededMaxNumTokens;
     }
 
     /** Builder for {@link PutDocumentStats}. */
     public static class Builder {
-        @NonNull final GeneralStats mGeneralStats;
+        @NonNull final GeneralStats.Builder mGeneralStatsBuilder;
         int mGenerateDocumentProtoLatencyMillis;
         int mRewriteDocumentTypesLatencyMillis;
         int mNativeLatencyMillis;
@@ -133,11 +138,19 @@
         int mNativeIndexMergeLatencyMillis;
         int mNativeDocumentSizeBytes;
         int mNativeNumTokensIndexed;
-        int mNativeNumTokensClipped;
+        boolean mNativeExceededMaxNumTokens;
 
-        /** Builder takes {@link GeneralStats} to hold general stats. */
-        public Builder(@NonNull GeneralStats generalStats) {
-            mGeneralStats = Preconditions.checkNotNull(generalStats);
+        /** Builder takes {@link GeneralStats.Builder}. */
+        public Builder(@NonNull String packageName, @NonNull String database) {
+            Preconditions.checkNotNull(packageName);
+            Preconditions.checkNotNull(database);
+            mGeneralStatsBuilder = new GeneralStats.Builder(packageName, database);
+        }
+
+        /** Returns {@link GeneralStats.Builder}. */
+        @NonNull
+        public GeneralStats.Builder getGeneralStatsBuilder() {
+            return mGeneralStatsBuilder;
         }
 
         /** Sets how much time we spend for generating document proto, in milliseconds. */
@@ -200,10 +213,13 @@
             return this;
         }
 
-        /** Sets number of tokens clipped for exceeding the max number. */
+        /**
+         * Sets whether the number of tokens to be indexed exceeded the max number of tokens per
+         * document.
+         */
         @NonNull
-        public Builder setNativeNumTokensClipped(int nativeNumTokensClipped) {
-            mNativeNumTokensClipped = nativeNumTokensClipped;
+        public Builder setNativeExceededMaxNumTokens(boolean nativeExceededMaxNumTokens) {
+            mNativeExceededMaxNumTokens = nativeExceededMaxNumTokens;
             return this;
         }
 
diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt
index 68531b6..0952215 100644
--- a/apex/appsearch/synced_jetpack_changeid.txt
+++ b/apex/appsearch/synced_jetpack_changeid.txt
@@ -1 +1 @@
-I1926fb1d13628607f7a513c8149b65dd86c98dd6
+I723a9d7b5e64329ab25b6d7627f3b2d222c31ac7
diff --git a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
index 2ce85ee..8c06338 100644
--- a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
@@ -136,6 +136,23 @@
     void restrictApp(@NonNull String packageName, int userId,
             @SystemForcedReasons int restrictReason);
 
+    /**
+     * Put the specified app in the
+     * {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED}
+     * bucket. If it has been used by the user recently, the restriction will delayed
+     * until an appropriate time. This should only be used in cases where
+     * {@link #restrictApp(String, int, int)} is not sufficient.
+     *
+     * @param mainReason     The main reason for restricting the app. Must be either {@link
+     *                       android.app.usage.UsageStatsManager#REASON_MAIN_FORCED_BY_SYSTEM} or
+     *                       {@link android.app.usage.UsageStatsManager#REASON_MAIN_FORCED_BY_USER}.
+     *                       Calls providing any other value will be ignored.
+     * @param restrictReason The restrictReason for restricting the app. Should be one of the
+     *                       UsageStatsManager.REASON_SUB_FORCED_SYSTEM_FLAG_* reasons.
+     */
+    void restrictApp(@NonNull String packageName, int userId, int mainReason,
+            @SystemForcedReasons int restrictReason);
+
     void addActiveDeviceAdmin(String adminPkg, int userId);
 
     void setActiveAdminApps(Set<String> adminPkgs, int userId);
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 82f2f69..2b08ba5 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -793,6 +793,13 @@
                         mDebuggableApps.remove(pkgName);
                     }
                 }
+            } else if (Intent.ACTION_USER_ADDED.equals(action)) {
+                final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
+                synchronized (mLock) {
+                    for (int c = 0; c < mControllers.size(); ++c) {
+                        mControllers.get(c).onUserAddedLocked(userId);
+                    }
+                }
             } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
                 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
                 if (DEBUG) {
@@ -1454,6 +1461,7 @@
             getContext().registerReceiverAsUser(
                     mBroadcastReceiver, UserHandle.ALL, filter, null, null);
             final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED);
+            userFilter.addAction(Intent.ACTION_USER_ADDED);
             getContext().registerReceiverAsUser(
                     mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
             try {
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 2f3ac22..2b79969 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
@@ -28,11 +28,11 @@
 import static com.android.server.job.JobSchedulerService.WORKING_INDEX;
 import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
 
+import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
-import android.app.ActivityManagerInternal;
 import android.app.AlarmManager;
 import android.app.AppGlobals;
 import android.app.IUidObserver;
@@ -43,7 +43,9 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.PackageManagerInternal;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
 import android.os.BatteryManager;
 import android.os.BatteryManagerInternal;
 import android.os.Handler;
@@ -119,6 +121,10 @@
     private static final String ALARM_TAG_CLEANUP = "*job.cleanup*";
     private static final String ALARM_TAG_QUOTA_CHECK = "*job.quota_check*";
 
+    private static final int SYSTEM_APP_CHECK_FLAGS =
+            PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+                    | PackageManager.GET_PERMISSIONS | PackageManager.MATCH_KNOWN_PACKAGES;
+
     /**
      * Standardize the output of userId-packageName combo.
      */
@@ -348,12 +354,20 @@
     private final SparseBooleanArray mTempAllowlistCache = new SparseBooleanArray();
 
     /**
-     * Mapping of app IDs to the when their temp allowlist grace period ends (in the elapsed
+     * Mapping of UIDs to the when their temp allowlist grace period ends (in the elapsed
      * realtime timebase).
      */
     private final SparseLongArray mTempAllowlistGraceCache = new SparseLongArray();
 
-    private final ActivityManagerInternal mActivityManagerInternal;
+    /** Current set of UIDs in the {@link ActivityManager#PROCESS_STATE_TOP} state. */
+    private final SparseBooleanArray mTopAppCache = new SparseBooleanArray();
+
+    /**
+     * Mapping of UIDs to the when their top app grace period ends (in the elapsed realtime
+     * timebase).
+     */
+    private final SparseLongArray mTopAppGraceCache = new SparseLongArray();
+
     private final AlarmManager mAlarmManager;
     private final ChargingTracker mChargeTracker;
     private final QcHandler mHandler;
@@ -412,7 +426,7 @@
                 }
             };
 
-    private final IUidObserver mUidObserver = new IUidObserver.Stub() {
+    private class QcUidObserver extends IUidObserver.Stub {
         @Override
         public void onUidStateChanged(int uid, int procState, long procStateSeq, int capability) {
             mHandler.obtainMessage(MSG_UID_PROCESS_STATE_CHANGED, uid, procState).sendToTarget();
@@ -433,7 +447,7 @@
         @Override
         public void onUidCachedChanged(int uid, boolean cached) {
         }
-    };
+    }
 
     private final BroadcastReceiver mPackageAddedReceiver = new BroadcastReceiver() {
         @Override
@@ -519,7 +533,9 @@
             QcConstants.DEFAULT_EJ_LIMIT_RESTRICTED_MS
     };
 
-    private long mEjLimitSpecialAdditionMs = QcConstants.DEFAULT_EJ_LIMIT_SPECIAL_ADDITION_MS;
+    private long mEjLimitAdditionInstallerMs = QcConstants.DEFAULT_EJ_LIMIT_ADDITION_INSTALLER_MS;
+
+    private long mEjLimitAdditionSpecialMs = QcConstants.DEFAULT_EJ_LIMIT_ADDITION_SPECIAL_MS;
 
     /**
      * The period of time used to calculate expedited job sessions. Apps can only have expedited job
@@ -548,12 +564,16 @@
      */
     private long mEJRewardNotificationSeenMs = QcConstants.DEFAULT_EJ_REWARD_NOTIFICATION_SEEN_MS;
 
-    private long mEJTempAllowlistGracePeriodMs =
-            QcConstants.DEFAULT_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS;
+    private long mEJGracePeriodTempAllowlistMs =
+            QcConstants.DEFAULT_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS;
 
-    /** The package verifier app. */
-    @Nullable
-    private String mPackageVerifier;
+    private long mEJGracePeriodTopAppMs = QcConstants.DEFAULT_EJ_GRACE_PERIOD_TOP_APP_MS;
+
+    /**
+     * List of system apps with the {@link android.Manifest.permission#INSTALL_PACKAGES} permission
+     * granted for each user.
+     */
+    private final SparseSetArray<String> mSystemInstallers = new SparseSetArray<>();
 
     /** An app has reached its quota. The message should contain a {@link Package} object. */
     @VisibleForTesting
@@ -586,7 +606,6 @@
         mHandler = new QcHandler(mContext.getMainLooper());
         mChargeTracker = new ChargingTracker();
         mChargeTracker.startTracking();
-        mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
         mQcConstants = new QcConstants();
         mBackgroundJobsController = backgroundJobsController;
@@ -606,9 +625,12 @@
         pai.registerTempAllowlistChangeListener(new TempAllowlistTracker());
 
         try {
-            ActivityManager.getService().registerUidObserver(mUidObserver,
+            ActivityManager.getService().registerUidObserver(new QcUidObserver(),
                     ActivityManager.UID_OBSERVER_PROCSTATE,
                     ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, null);
+            ActivityManager.getService().registerUidObserver(new QcUidObserver(),
+                    ActivityManager.UID_OBSERVER_PROCSTATE,
+                    ActivityManager.PROCESS_STATE_TOP, null);
         } catch (RemoteException e) {
             // ignored; both services live in system_server
         }
@@ -616,11 +638,8 @@
 
     @Override
     public void onSystemServicesReady() {
-        String[] pkgNames = LocalServices.getService(PackageManagerInternal.class)
-                .getKnownPackageNames(
-                        PackageManagerInternal.PACKAGE_VERIFIER, UserHandle.USER_SYSTEM);
         synchronized (mLock) {
-            mPackageVerifier = ArrayUtils.firstOrNull(pkgNames);
+            cacheInstallerPackagesLocked(UserHandle.USER_SYSTEM);
         }
     }
 
@@ -658,7 +677,7 @@
         }
 
         final int uid = jobStatus.getSourceUid();
-        if (mActivityManagerInternal.getUidProcessState(uid) <= ActivityManager.PROCESS_STATE_TOP) {
+        if (mTopAppCache.get(uid)) {
             if (DEBUG) {
                 Slog.d(TAG, jobStatus.toShortString() + " is top started job");
             }
@@ -715,6 +734,13 @@
         mUidToPackageCache.remove(uid);
         mTempAllowlistCache.delete(uid);
         mTempAllowlistGraceCache.delete(uid);
+        mTopAppCache.delete(uid);
+        mTopAppGraceCache.delete(uid);
+    }
+
+    @Override
+    public void onUserAddedLocked(int userId) {
+        cacheInstallerPackagesLocked(userId);
     }
 
     @Override
@@ -728,6 +754,7 @@
         mExecutionStatsCache.delete(userId);
         mEJStats.delete(userId);
         mUidToPackageCache.clear();
+        mSystemInstallers.remove(userId);
     }
 
     /** Drop all historical stats and stop tracking any active sessions for the specified app. */
@@ -754,6 +781,22 @@
         mEJStats.delete(userId, packageName);
     }
 
+    private void cacheInstallerPackagesLocked(int userId) {
+        final List<PackageInfo> packages = mContext.getPackageManager()
+                .getInstalledPackagesAsUser(SYSTEM_APP_CHECK_FLAGS, userId);
+        for (int i = packages.size() - 1; i >= 0; --i) {
+            final PackageInfo pi = packages.get(i);
+            final ApplicationInfo ai = pi.applicationInfo;
+            final int idx = ArrayUtils.indexOf(
+                    pi.requestedPermissions, Manifest.permission.INSTALL_PACKAGES);
+
+            if (idx >= 0 && ai != null && PackageManager.PERMISSION_GRANTED
+                    == mContext.checkPermission(Manifest.permission.INSTALL_PACKAGES, -1, ai.uid)) {
+                mSystemInstallers.add(UserHandle.getUserId(ai.uid), pi.packageName);
+            }
+        }
+    }
+
     private boolean isUidInForeground(int uid) {
         if (UserHandle.isCore(uid)) {
             return true;
@@ -770,14 +813,10 @@
 
     /** Returns the maximum amount of time this job could run for. */
     public long getMaxJobExecutionTimeMsLocked(@NonNull final JobStatus jobStatus) {
-        // Need to look at current proc state as well in the case where the job hasn't started yet.
-        final boolean isTop = mActivityManagerInternal
-                .getUidProcessState(jobStatus.getSourceUid()) <= ActivityManager.PROCESS_STATE_TOP;
-
         if (!jobStatus.shouldTreatAsExpeditedJob()) {
             // If quota is currently "free", then the job can run for the full amount of time.
             if (mChargeTracker.isCharging()
-                    || isTop
+                    || mTopAppCache.get(jobStatus.getSourceUid())
                     || isTopStartedJobLocked(jobStatus)
                     || isUidInForeground(jobStatus.getSourceUid())) {
                 return mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS;
@@ -790,7 +829,7 @@
         if (mChargeTracker.isCharging()) {
             return mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS;
         }
-        if (isTop || isTopStartedJobLocked(jobStatus)) {
+        if (mTopAppCache.get(jobStatus.getSourceUid()) || isTopStartedJobLocked(jobStatus)) {
             return Math.max(mEJLimitsMs[ACTIVE_INDEX] / 2,
                     getTimeUntilEJQuotaConsumedLocked(
                             jobStatus.getSourceUserId(), jobStatus.getSourcePackageName()));
@@ -817,14 +856,23 @@
         if (isTopStartedJobLocked(jobStatus) || isUidInForeground(jobStatus.getSourceUid())) {
             return true;
         }
+
+        final long nowElapsed = sElapsedRealtimeClock.millis();
         final long tempAllowlistGracePeriodEndElapsed =
                 mTempAllowlistGraceCache.get(jobStatus.getSourceUid());
         final boolean hasTempAllowlistExemption = mTempAllowlistCache.get(jobStatus.getSourceUid())
-                || sElapsedRealtimeClock.millis() < tempAllowlistGracePeriodEndElapsed;
+                || nowElapsed < tempAllowlistGracePeriodEndElapsed;
         if (hasTempAllowlistExemption) {
             return true;
         }
 
+        final long topAppGracePeriodEndElapsed = mTopAppGraceCache.get(jobStatus.getSourceUid());
+        final boolean hasTopAppExemption = mTopAppCache.get(jobStatus.getSourceUid())
+                || nowElapsed < topAppGracePeriodEndElapsed;
+        if (hasTopAppExemption) {
+            return true;
+        }
+
         Timer ejTimer = mEJPkgTimers.get(jobStatus.getSourceUserId(),
                 jobStatus.getSourcePackageName());
         // Any already executing expedited jobs should be allowed to finish.
@@ -944,7 +992,8 @@
         if (quota.getStandbyBucketLocked() == NEVER_INDEX) {
             return 0;
         }
-        final long limitMs = getEJLimitMsLocked(packageName, quota.getStandbyBucketLocked());
+        final long limitMs =
+                getEJLimitMsLocked(userId, packageName, quota.getStandbyBucketLocked());
         long remainingMs = limitMs - quota.getTallyLocked();
 
         // Stale sessions may still be factored into tally. Make sure they're removed.
@@ -982,10 +1031,11 @@
         return remainingMs - timer.getCurrentDuration(sElapsedRealtimeClock.millis());
     }
 
-    private long getEJLimitMsLocked(@NonNull final String packageName, final int standbyBucket) {
+    private long getEJLimitMsLocked(final int userId, @NonNull final String packageName,
+            final int standbyBucket) {
         final long baseLimitMs = mEJLimitsMs[standbyBucket];
-        if (packageName.equals(mPackageVerifier)) {
-            return baseLimitMs + mEjLimitSpecialAdditionMs;
+        if (mSystemInstallers.contains(userId, packageName)) {
+            return baseLimitMs + mEjLimitAdditionInstallerMs;
         }
         return baseLimitMs;
     }
@@ -1098,7 +1148,8 @@
 
         final long nowElapsed = sElapsedRealtimeClock.millis();
         ShrinkableDebits quota = getEJDebitsLocked(userId, packageName);
-        final long limitMs = getEJLimitMsLocked(packageName, quota.getStandbyBucketLocked());
+        final long limitMs =
+                getEJLimitMsLocked(userId, packageName, quota.getStandbyBucketLocked());
         final long startWindowElapsed = Math.max(0, nowElapsed - mEJLimitWindowSizeMs);
         long remainingDeadSpaceMs = remainingExecutionTimeMs;
         // Total time looked at where a session wouldn't be phasing out.
@@ -1725,7 +1776,8 @@
             inRegularQuotaTimeElapsed = inQuotaTimeElapsed;
         }
         if (remainingEJQuota <= 0) {
-            final long limitMs = getEJLimitMsLocked(packageName, standbyBucket) - mQuotaBufferMs;
+            final long limitMs =
+                    getEJLimitMsLocked(userId, packageName, standbyBucket) - mQuotaBufferMs;
             long sumMs = 0;
             final Timer ejTimer = mEJPkgTimers.get(userId, packageName);
             if (ejTimer != null && ejTimer.isActive()) {
@@ -2101,8 +2153,12 @@
             final boolean hasTempAllowlistExemption = !mRegularJobTimer
                     && (mTempAllowlistCache.get(mUid)
                     || nowElapsed < tempAllowlistGracePeriodEndElapsed);
+            final long topAppGracePeriodEndElapsed = mTopAppGraceCache.get(mUid);
+            final boolean hasTopAppExemption = !mRegularJobTimer
+                    && (mTopAppCache.get(mUid) || nowElapsed < topAppGracePeriodEndElapsed);
             return (standbyBucket == RESTRICTED_INDEX || !mChargeTracker.isCharging())
-                    && !mForegroundUids.get(mUid) && !hasTempAllowlistExemption;
+                    && !mForegroundUids.get(mUid) && !hasTempAllowlistExemption
+                    && !hasTopAppExemption;
         }
 
         void onStateChangedLocked(long nowElapsed, boolean isQuotaFree) {
@@ -2421,11 +2477,11 @@
         public void onAppRemoved(int uid) {
             synchronized (mLock) {
                 final long nowElapsed = sElapsedRealtimeClock.millis();
-                final long endElapsed = nowElapsed + mEJTempAllowlistGracePeriodMs;
+                final long endElapsed = nowElapsed + mEJGracePeriodTempAllowlistMs;
                 mTempAllowlistCache.delete(uid);
                 mTempAllowlistGraceCache.put(uid, endElapsed);
                 Message msg = mHandler.obtainMessage(MSG_END_GRACE_PERIOD, uid, 0);
-                mHandler.sendMessageDelayed(msg, mEJTempAllowlistGracePeriodMs);
+                mHandler.sendMessageDelayed(msg, mEJGracePeriodTempAllowlistMs);
             }
         }
     }
@@ -2571,12 +2627,37 @@
 
                         synchronized (mLock) {
                             boolean isQuotaFree;
-                            if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
+                            if (procState <= ActivityManager.PROCESS_STATE_TOP) {
+                                mTopAppCache.put(uid, true);
+                                mTopAppGraceCache.delete(uid);
+                                if (mForegroundUids.get(uid)) {
+                                    // Went from FGS to TOP. We don't need to reprocess timers or
+                                    // jobs.
+                                    break;
+                                }
                                 mForegroundUids.put(uid, true);
                                 isQuotaFree = true;
                             } else {
-                                mForegroundUids.delete(uid);
-                                isQuotaFree = false;
+                                final boolean reprocess;
+                                if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
+                                    reprocess = !mForegroundUids.get(uid);
+                                    mForegroundUids.put(uid, true);
+                                    isQuotaFree = true;
+                                } else {
+                                    reprocess = true;
+                                    mForegroundUids.delete(uid);
+                                    isQuotaFree = false;
+                                }
+                                if (mTopAppCache.get(uid)) {
+                                    final long endElapsed = nowElapsed + mEJGracePeriodTopAppMs;
+                                    mTopAppCache.delete(uid);
+                                    mTopAppGraceCache.put(uid, endElapsed);
+                                    sendMessageDelayed(obtainMessage(MSG_END_GRACE_PERIOD, uid, 0),
+                                            mEJGracePeriodTopAppMs);
+                                }
+                                if (!reprocess) {
+                                    break;
+                                }
                             }
                             // Update Timers first.
                             if (mPkgTimers.indexOfKey(userId) >= 0
@@ -2644,20 +2725,31 @@
                     case MSG_END_GRACE_PERIOD: {
                         final int uid = msg.arg1;
                         synchronized (mLock) {
-                            if (mTempAllowlistCache.get(uid)) {
-                                // App added back to the temp allowlist during the grace period.
+                            if (mTempAllowlistCache.get(uid) || mTopAppCache.get(uid)) {
+                                // App added back to the temp allowlist or became top again
+                                // during the grace period.
                                 if (DEBUG) {
                                     Slog.d(TAG, uid + " is still allowed");
                                 }
                                 break;
                             }
+                            final long nowElapsed = sElapsedRealtimeClock.millis();
+                            if (nowElapsed < mTempAllowlistGraceCache.get(uid)
+                                    || nowElapsed < mTopAppGraceCache.get(uid)) {
+                                // One of the grace periods is still in effect.
+                                if (DEBUG) {
+                                    Slog.d(TAG, uid + " is still in grace period");
+                                }
+                                break;
+                            }
                             if (DEBUG) {
                                 Slog.d(TAG, uid + " is now out of grace period");
                             }
+                            mTempAllowlistGraceCache.delete(uid);
+                            mTopAppGraceCache.delete(uid);
                             final ArraySet<String> packages = getPackagesForUidLocked(uid);
                             if (packages != null) {
                                 final int userId = UserHandle.getUserId(uid);
-                                final long nowElapsed = sElapsedRealtimeClock.millis();
                                 for (int i = packages.size() - 1; i >= 0; --i) {
                                     Timer t = mEJPkgTimers.get(userId, packages.valueAt(i));
                                     if (t != null) {
@@ -2971,8 +3063,11 @@
         static final String KEY_EJ_LIMIT_RESTRICTED_MS =
                 QC_CONSTANT_PREFIX + "ej_limit_restricted_ms";
         @VisibleForTesting
-        static final String KEY_EJ_LIMIT_SPECIAL_ADDITION_MS =
-                QC_CONSTANT_PREFIX + "ej_limit_special_addition_ms";
+        static final String KEY_EJ_LIMIT_ADDITION_SPECIAL_MS =
+                QC_CONSTANT_PREFIX + "ej_limit_addition_special_ms";
+        @VisibleForTesting
+        static final String KEY_EJ_LIMIT_ADDITION_INSTALLER_MS =
+                QC_CONSTANT_PREFIX + "ej_limit_addition_installer_ms";
         @VisibleForTesting
         static final String KEY_EJ_WINDOW_SIZE_MS =
                 QC_CONSTANT_PREFIX + "ej_window_size_ms";
@@ -2989,8 +3084,11 @@
         static final String KEY_EJ_REWARD_NOTIFICATION_SEEN_MS =
                 QC_CONSTANT_PREFIX + "ej_reward_notification_seen_ms";
         @VisibleForTesting
-        static final String KEY_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS =
-                QC_CONSTANT_PREFIX + "ej_temp_allowlist_grace_period_ms";
+        static final String KEY_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS =
+                QC_CONSTANT_PREFIX + "ej_grace_period_temp_allowlist_ms";
+        @VisibleForTesting
+        static final String KEY_EJ_GRACE_PERIOD_TOP_APP_MS =
+                QC_CONSTANT_PREFIX + "ej_grace_period_top_app_ms";
 
         private static final long DEFAULT_ALLOWED_TIME_PER_PERIOD_MS =
                 10 * 60 * 1000L; // 10 minutes
@@ -3037,13 +3135,15 @@
         private static final long DEFAULT_EJ_LIMIT_FREQUENT_MS = 10 * MINUTE_IN_MILLIS;
         private static final long DEFAULT_EJ_LIMIT_RARE_MS = DEFAULT_EJ_LIMIT_FREQUENT_MS;
         private static final long DEFAULT_EJ_LIMIT_RESTRICTED_MS = 5 * MINUTE_IN_MILLIS;
-        private static final long DEFAULT_EJ_LIMIT_SPECIAL_ADDITION_MS = 30 * MINUTE_IN_MILLIS;
+        private static final long DEFAULT_EJ_LIMIT_ADDITION_SPECIAL_MS = 15 * MINUTE_IN_MILLIS;
+        private static final long DEFAULT_EJ_LIMIT_ADDITION_INSTALLER_MS = 30 * MINUTE_IN_MILLIS;
         private static final long DEFAULT_EJ_WINDOW_SIZE_MS = 24 * HOUR_IN_MILLIS;
         private static final long DEFAULT_EJ_TOP_APP_TIME_CHUNK_SIZE_MS = 30 * SECOND_IN_MILLIS;
         private static final long DEFAULT_EJ_REWARD_TOP_APP_MS = 10 * SECOND_IN_MILLIS;
         private static final long DEFAULT_EJ_REWARD_INTERACTION_MS = 15 * SECOND_IN_MILLIS;
         private static final long DEFAULT_EJ_REWARD_NOTIFICATION_SEEN_MS = 0;
-        private static final long DEFAULT_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS = 3 * MINUTE_IN_MILLIS;
+        private static final long DEFAULT_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS = 3 * MINUTE_IN_MILLIS;
+        private static final long DEFAULT_EJ_GRACE_PERIOD_TOP_APP_MS = 1 * MINUTE_IN_MILLIS;
 
         /** How much time each app will have to run jobs within their standby bucket window. */
         public long ALLOWED_TIME_PER_PERIOD_MS = DEFAULT_ALLOWED_TIME_PER_PERIOD_MS;
@@ -3241,7 +3341,13 @@
         /**
          * How much additional EJ quota special, critical apps should get.
          */
-        public long EJ_LIMIT_SPECIAL_ADDITION_MS = DEFAULT_EJ_LIMIT_SPECIAL_ADDITION_MS;
+        public long EJ_LIMIT_ADDITION_SPECIAL_MS = DEFAULT_EJ_LIMIT_ADDITION_SPECIAL_MS;
+
+        /**
+         * How much additional EJ quota system installers (with the INSTALL_PACKAGES permission)
+         * should get.
+         */
+        public long EJ_LIMIT_ADDITION_INSTALLER_MS = DEFAULT_EJ_LIMIT_ADDITION_INSTALLER_MS;
 
         /**
          * The period of time used to calculate expedited job sessions. Apps can only have expedited
@@ -3275,7 +3381,12 @@
          * How much additional grace period to add to the end of an app's temp allowlist
          * duration.
          */
-        public long EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS = DEFAULT_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS;
+        public long EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS = DEFAULT_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS;
+
+        /**
+         * How much additional grace period to give an app when it leaves the TOP state.
+         */
+        public long EJ_GRACE_PERIOD_TOP_APP_MS = DEFAULT_EJ_GRACE_PERIOD_TOP_APP_MS;
 
         public void processConstantLocked(@NonNull DeviceConfig.Properties properties,
                 @NonNull String key) {
@@ -3302,7 +3413,8 @@
                 case KEY_EJ_LIMIT_FREQUENT_MS:
                 case KEY_EJ_LIMIT_RARE_MS:
                 case KEY_EJ_LIMIT_RESTRICTED_MS:
-                case KEY_EJ_LIMIT_SPECIAL_ADDITION_MS:
+                case KEY_EJ_LIMIT_ADDITION_SPECIAL_MS:
+                case KEY_EJ_LIMIT_ADDITION_INSTALLER_MS:
                 case KEY_EJ_WINDOW_SIZE_MS:
                     updateEJLimitConstantsLocked();
                     break;
@@ -3470,13 +3582,21 @@
                     mEJRewardNotificationSeenMs = Math.min(5 * MINUTE_IN_MILLIS,
                             Math.max(0, EJ_REWARD_NOTIFICATION_SEEN_MS));
                     break;
-                case KEY_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS:
+                case KEY_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS:
                     // We don't need to re-evaluate execution stats or constraint status for this.
-                    EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS =
-                            properties.getLong(key, DEFAULT_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS);
+                    EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS =
+                            properties.getLong(key, DEFAULT_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS);
                     // Limit grace period to be in the range [0 minutes, 1 hour].
-                    mEJTempAllowlistGracePeriodMs = Math.min(HOUR_IN_MILLIS,
-                            Math.max(0, EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS));
+                    mEJGracePeriodTempAllowlistMs = Math.min(HOUR_IN_MILLIS,
+                            Math.max(0, EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS));
+                    break;
+                case KEY_EJ_GRACE_PERIOD_TOP_APP_MS:
+                    // We don't need to re-evaluate execution stats or constraint status for this.
+                    EJ_GRACE_PERIOD_TOP_APP_MS =
+                            properties.getLong(key, DEFAULT_EJ_GRACE_PERIOD_TOP_APP_MS);
+                    // Limit grace period to be in the range [0 minutes, 1 hour].
+                    mEJGracePeriodTopAppMs = Math.min(HOUR_IN_MILLIS,
+                            Math.max(0, EJ_GRACE_PERIOD_TOP_APP_MS));
                     break;
             }
         }
@@ -3629,7 +3749,8 @@
                     DeviceConfig.NAMESPACE_JOB_SCHEDULER,
                     KEY_EJ_LIMIT_ACTIVE_MS, KEY_EJ_LIMIT_WORKING_MS,
                     KEY_EJ_LIMIT_FREQUENT_MS, KEY_EJ_LIMIT_RARE_MS,
-                    KEY_EJ_LIMIT_RESTRICTED_MS, KEY_EJ_LIMIT_SPECIAL_ADDITION_MS,
+                    KEY_EJ_LIMIT_RESTRICTED_MS, KEY_EJ_LIMIT_ADDITION_SPECIAL_MS,
+                    KEY_EJ_LIMIT_ADDITION_INSTALLER_MS,
                     KEY_EJ_WINDOW_SIZE_MS);
             EJ_LIMIT_ACTIVE_MS = properties.getLong(
                     KEY_EJ_LIMIT_ACTIVE_MS, DEFAULT_EJ_LIMIT_ACTIVE_MS);
@@ -3641,8 +3762,10 @@
                     KEY_EJ_LIMIT_RARE_MS, DEFAULT_EJ_LIMIT_RARE_MS);
             EJ_LIMIT_RESTRICTED_MS = properties.getLong(
                     KEY_EJ_LIMIT_RESTRICTED_MS, DEFAULT_EJ_LIMIT_RESTRICTED_MS);
-            EJ_LIMIT_SPECIAL_ADDITION_MS = properties.getLong(
-                    KEY_EJ_LIMIT_SPECIAL_ADDITION_MS, DEFAULT_EJ_LIMIT_SPECIAL_ADDITION_MS);
+            EJ_LIMIT_ADDITION_INSTALLER_MS = properties.getLong(
+                    KEY_EJ_LIMIT_ADDITION_INSTALLER_MS, DEFAULT_EJ_LIMIT_ADDITION_INSTALLER_MS);
+            EJ_LIMIT_ADDITION_SPECIAL_MS = properties.getLong(
+                    KEY_EJ_LIMIT_ADDITION_SPECIAL_MS, DEFAULT_EJ_LIMIT_ADDITION_SPECIAL_MS);
             EJ_WINDOW_SIZE_MS = properties.getLong(
                     KEY_EJ_WINDOW_SIZE_MS, DEFAULT_EJ_WINDOW_SIZE_MS);
 
@@ -3688,11 +3811,17 @@
                 mEJLimitsMs[RESTRICTED_INDEX] = newRestrictedLimitMs;
                 mShouldReevaluateConstraints = true;
             }
-            // The addition must be in the range [0 minutes, window size - active limit].
-            long newSpecialAdditionMs = Math.max(0,
-                    Math.min(newWindowSizeMs - newActiveLimitMs, EJ_LIMIT_SPECIAL_ADDITION_MS));
-            if (mEjLimitSpecialAdditionMs != newSpecialAdditionMs) {
-                mEjLimitSpecialAdditionMs = newSpecialAdditionMs;
+            // The additions must be in the range [0 minutes, window size - active limit].
+            long newAdditionInstallerMs = Math.max(0,
+                    Math.min(newWindowSizeMs - newActiveLimitMs, EJ_LIMIT_ADDITION_INSTALLER_MS));
+            if (mEjLimitAdditionInstallerMs != newAdditionInstallerMs) {
+                mEjLimitAdditionInstallerMs = newAdditionInstallerMs;
+                mShouldReevaluateConstraints = true;
+            }
+            long newAdditionSpecialMs = Math.max(0,
+                    Math.min(newWindowSizeMs - newActiveLimitMs, EJ_LIMIT_ADDITION_SPECIAL_MS));
+            if (mEjLimitAdditionSpecialMs != newAdditionSpecialMs) {
+                mEjLimitAdditionSpecialMs = newAdditionSpecialMs;
                 mShouldReevaluateConstraints = true;
             }
         }
@@ -3733,14 +3862,16 @@
             pw.print(KEY_EJ_LIMIT_FREQUENT_MS, EJ_LIMIT_FREQUENT_MS).println();
             pw.print(KEY_EJ_LIMIT_RARE_MS, EJ_LIMIT_RARE_MS).println();
             pw.print(KEY_EJ_LIMIT_RESTRICTED_MS, EJ_LIMIT_RESTRICTED_MS).println();
-            pw.print(KEY_EJ_LIMIT_SPECIAL_ADDITION_MS, EJ_LIMIT_SPECIAL_ADDITION_MS).println();
+            pw.print(KEY_EJ_LIMIT_ADDITION_INSTALLER_MS, EJ_LIMIT_ADDITION_INSTALLER_MS).println();
+            pw.print(KEY_EJ_LIMIT_ADDITION_SPECIAL_MS, EJ_LIMIT_ADDITION_SPECIAL_MS).println();
             pw.print(KEY_EJ_WINDOW_SIZE_MS, EJ_WINDOW_SIZE_MS).println();
             pw.print(KEY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS, EJ_TOP_APP_TIME_CHUNK_SIZE_MS).println();
             pw.print(KEY_EJ_REWARD_TOP_APP_MS, EJ_REWARD_TOP_APP_MS).println();
             pw.print(KEY_EJ_REWARD_INTERACTION_MS, EJ_REWARD_INTERACTION_MS).println();
             pw.print(KEY_EJ_REWARD_NOTIFICATION_SEEN_MS, EJ_REWARD_NOTIFICATION_SEEN_MS).println();
-            pw.print(KEY_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS,
-                    EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS).println();
+            pw.print(KEY_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS,
+                    EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS).println();
+            pw.print(KEY_EJ_GRACE_PERIOD_TOP_APP_MS, EJ_GRACE_PERIOD_TOP_APP_MS).println();
 
             pw.decreaseIndent();
         }
@@ -3853,14 +3984,29 @@
     }
 
     @VisibleForTesting
+    long getEJGracePeriodTempAllowlistMs() {
+        return mEJGracePeriodTempAllowlistMs;
+    }
+
+    @VisibleForTesting
+    long getEJGracePeriodTopAppMs() {
+        return mEJGracePeriodTopAppMs;
+    }
+
+    @VisibleForTesting
     @NonNull
     long[] getEJLimitsMs() {
         return mEJLimitsMs;
     }
 
     @VisibleForTesting
-    long getEjLimitSpecialAdditionMs() {
-        return mEjLimitSpecialAdditionMs;
+    long getEjLimitAdditionInstallerMs() {
+        return mEjLimitAdditionInstallerMs;
+    }
+
+    @VisibleForTesting
+    long getEjLimitAdditionSpecialMs() {
+        return mEjLimitAdditionSpecialMs;
     }
 
     @VisibleForTesting
@@ -3888,11 +4034,6 @@
     }
 
     @VisibleForTesting
-    long getEJTempAllowlistGracePeriodMs() {
-        return mEJTempAllowlistGracePeriodMs;
-    }
-
-    @VisibleForTesting
     @Nullable
     List<TimingSession> getEJTimingSessions(int userId, String packageName) {
         return mEJTimingSessions.get(userId, packageName);
@@ -3964,6 +4105,17 @@
         pw.println(mForegroundUids.toString());
         pw.println();
 
+        pw.print("Cached top apps: ");
+        pw.println(mTopAppCache.toString());
+        pw.print("Cached top app grace period: ");
+        pw.println(mTopAppGraceCache.toString());
+
+        pw.print("Cached temp allowlist: ");
+        pw.println(mTempAllowlistCache.toString());
+        pw.print("Cached temp allowlist grace period: ");
+        pw.println(mTempAllowlistGraceCache.toString());
+        pw.println();
+
         pw.println("Cached UID->package map:");
         pw.increaseIndent();
         for (int i = 0; i < mUidToPackageCache.size(); ++i) {
@@ -3975,10 +4127,10 @@
         pw.decreaseIndent();
         pw.println();
 
-        pw.print("Cached temp allowlist: ");
-        pw.println(mTempAllowlistCache.toString());
-        pw.print("Cached temp allowlist grace period: ");
-        pw.println(mTempAllowlistGraceCache.toString());
+        pw.println("Special apps:");
+        pw.increaseIndent();
+        pw.print("System installers", mSystemInstallers.toString());
+        pw.decreaseIndent();
 
         pw.println();
         mTrackedJobs.forEach((jobs) -> {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java
index 56b3090..a33ba5b 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java
@@ -103,6 +103,10 @@
     public void onAppRemovedLocked(String packageName, int uid) {
     }
 
+    /** Called when a user is added to the device. */
+    public void onUserAddedLocked(int userId) {
+    }
+
     /** Called when a user is removed from the device. */
     public void onUserRemovedLocked(int userId) {
     }
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 1a808c9..24f7b37 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -1343,13 +1343,24 @@
     @Override
     public void restrictApp(@NonNull String packageName, int userId,
             @SystemForcedReasons int restrictReason) {
+        restrictApp(packageName, userId, REASON_MAIN_FORCED_BY_SYSTEM, restrictReason);
+    }
+
+    @Override
+    public void restrictApp(@NonNull String packageName, int userId, int mainReason,
+            @SystemForcedReasons int restrictReason) {
+        if (mainReason != REASON_MAIN_FORCED_BY_SYSTEM
+                && mainReason != REASON_MAIN_FORCED_BY_USER) {
+            Slog.e(TAG, "Tried to restrict app " + packageName + " for an unsupported reason");
+            return;
+        }
         // If the package is not installed, don't allow the bucket to be set.
         if (!mInjector.isPackageInstalled(packageName, 0, userId)) {
             Slog.e(TAG, "Tried to restrict uninstalled app: " + packageName);
             return;
         }
 
-        final int reason = REASON_MAIN_FORCED_BY_SYSTEM | (REASON_SUB_MASK & restrictReason);
+        final int reason = (REASON_MAIN_MASK & mainReason) | (REASON_SUB_MASK & restrictReason);
         final long nowElapsed = mInjector.elapsedRealtime();
         final int bucket = mAllowRestrictedBucket ? STANDBY_BUCKET_RESTRICTED : STANDBY_BUCKET_RARE;
         setAppStandbyBucket(packageName, userId, bucket, reason, nowElapsed, false);
diff --git a/apex/media/framework/api/system-current.txt b/apex/media/framework/api/system-current.txt
index 1d912eb..ad68169 100644
--- a/apex/media/framework/api/system-current.txt
+++ b/apex/media/framework/api/system-current.txt
@@ -18,11 +18,9 @@
     method @NonNull public android.net.Uri getSourceUri();
   }
 
-  public static class MediaTranscodeManager.TranscodingRequest.MediaFormatResolver {
-    ctor public MediaTranscodeManager.TranscodingRequest.MediaFormatResolver();
+  public static class MediaTranscodeManager.TranscodingRequest.VideoFormatResolver {
+    ctor public MediaTranscodeManager.TranscodingRequest.VideoFormatResolver(@NonNull android.media.ApplicationMediaCapabilities, @NonNull android.media.MediaFormat);
     method @Nullable public android.media.MediaFormat resolveVideoFormat();
-    method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.MediaFormatResolver setClientCapabilities(@NonNull android.media.ApplicationMediaCapabilities);
-    method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.MediaFormatResolver setSourceVideoFormatHint(@NonNull android.media.MediaFormat);
     method public boolean shouldTranscode();
   }
 
@@ -34,7 +32,6 @@
     method public int getSessionId();
     method public int getStatus();
     method public void setOnProgressUpdateListener(@NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodeManager.TranscodingSession.OnProgressUpdateListener);
-    method public void setOnProgressUpdateListener(int, @NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodeManager.TranscodingSession.OnProgressUpdateListener);
     field public static final int ERROR_DROPPED_BY_SERVICE = 1; // 0x1
     field public static final int ERROR_NONE = 0; // 0x0
     field public static final int ERROR_SERVICE_DIED = 2; // 0x2
diff --git a/apex/media/framework/java/android/media/MediaTranscodeManager.java b/apex/media/framework/java/android/media/MediaTranscodeManager.java
index 79e0d58..7f4685e 100644
--- a/apex/media/framework/java/android/media/MediaTranscodeManager.java
+++ b/apex/media/framework/java/android/media/MediaTranscodeManager.java
@@ -822,83 +822,102 @@
         }
 
         /**
-         * Helper class for deciding if transcoding is needed, and if so, the track
+         * Abstract base class for all the format resolvers.
+         */
+        abstract static class MediaFormatResolver {
+            private @NonNull ApplicationMediaCapabilities mClientCaps;
+
+            /**
+             * Prevents public constructor access.
+             */
+            /* package private */ MediaFormatResolver() {
+            }
+
+            /**
+             * Constructs MediaFormatResolver object.
+             *
+             * @param clientCaps An ApplicationMediaCapabilities object containing the client's
+             *                   capabilities.
+             */
+            MediaFormatResolver(@NonNull ApplicationMediaCapabilities clientCaps) {
+                if (clientCaps == null) {
+                    throw new IllegalArgumentException("Client capabilities must not be null");
+                }
+                mClientCaps = clientCaps;
+            }
+
+            /**
+             * Returns the client capabilities.
+             */
+            @NonNull
+            /* package */ ApplicationMediaCapabilities getClientCapabilities() {
+                return mClientCaps;
+            }
+
+            abstract boolean shouldTranscode();
+        }
+
+        /**
+         * VideoFormatResolver for deciding if video transcoding is needed, and if so, the track
          * formats to use.
          */
-        public static class MediaFormatResolver {
+        public static class VideoFormatResolver extends MediaFormatResolver {
             private static final int BIT_RATE = 20000000;            // 20Mbps
 
             private MediaFormat mSrcVideoFormatHint;
             private MediaFormat mSrcAudioFormatHint;
-            private ApplicationMediaCapabilities mClientCaps;
 
             /**
-             * Sets the abilities of the client consuming the media. Must be called
-             * before {@link #shouldTranscode()} or {@link #resolveVideoFormat()}.
+             * Constructs a new VideoFormatResolver object.
              *
              * @param clientCaps An ApplicationMediaCapabilities object containing the client's
              *                   capabilities.
-             * @return the same VideoFormatResolver instance.
+             * @param srcVideoFormatHint A MediaFormat object containing information about the
+             *                           source's video track format that could affect the
+             *                           transcoding decision. Such information could include video
+             *                           codec types, color spaces, whether special format info (eg.
+             *                           slow-motion markers) are present, etc.. If a particular
+             *                           information is not present, it will not be used to make the
+             *                           decision.
              */
-            @NonNull
-            public MediaFormatResolver setClientCapabilities(
-                    @NonNull ApplicationMediaCapabilities clientCaps) {
-                mClientCaps = clientCaps;
-                return this;
+            public VideoFormatResolver(@NonNull ApplicationMediaCapabilities clientCaps,
+                    @NonNull MediaFormat srcVideoFormatHint) {
+                super(clientCaps);
+                mSrcVideoFormatHint = srcVideoFormatHint;
             }
 
             /**
-             * Sets the video format hint about the source. Must be called before
-             * {@link #shouldTranscode()} or {@link #resolveVideoFormat()}.
+             * Constructs a new VideoFormatResolver object.
              *
-             * @param format A MediaFormat object containing information about the source's
-             *               video track format that could affect the transcoding decision.
-             *               Such information could include video codec types, color spaces,
-             *               whether special format info (eg. slow-motion markers) are present,
-             *               etc.. If a particular information is not present, it will not be
-             *               used to make the decision.
-             * @return the same MediaFormatResolver instance.
-             */
-            @NonNull
-            public MediaFormatResolver setSourceVideoFormatHint(@NonNull MediaFormat format) {
-                mSrcVideoFormatHint = format;
-                return this;
-            }
-
-            /**
-             * Sets the audio format hint about the source.
-             *
-             * @param format A MediaFormat object containing information about the source's
-             *               audio track format that could affect the transcoding decision.
-             * @return the same MediaFormatResolver instance.
+             * @param clientCaps An ApplicationMediaCapabilities object containing the client's
+             *                   capabilities.
+             * @param srcVideoFormatHint A MediaFormat object containing information about the
+             *                           source's video track format that could affect the
+             *                           transcoding decision. Such information could include video
+             *                           codec types, color spaces, whether special format info (eg.
+             *                           slow-motion markers) are present, etc.. If a particular
+             *                           information is not present, it will not be used to make the
+             *                           decision.
+             * @param srcAudioFormatHint A MediaFormat object containing information about the
+             *                           source's audio track format that could affect the
+             *                           transcoding decision.
              * @hide
              */
-            @NonNull
-            public MediaFormatResolver setSourceAudioFormatHint(@NonNull MediaFormat format) {
-                mSrcAudioFormatHint = format;
-                return this;
+            VideoFormatResolver(@NonNull ApplicationMediaCapabilities clientCaps,
+                    @NonNull MediaFormat srcVideoFormatHint,
+                    @NonNull MediaFormat srcAudioFormatHint) {
+                super(clientCaps);
+                mSrcVideoFormatHint = srcVideoFormatHint;
+                mSrcAudioFormatHint = srcAudioFormatHint;
             }
 
             /**
              * Returns whether the source content should be transcoded.
              *
              * @return true if the source should be transcoded.
-             * @throws UnsupportedOperationException
-             *         if {@link #setClientCapabilities(ApplicationMediaCapabilities)}
-             *         or {@link #setSourceVideoFormatHint(MediaFormat)} was not called.
              */
             public boolean shouldTranscode() {
-                if (mClientCaps == null) {
-                    throw new UnsupportedOperationException(
-                            "Client caps must be set!");
-                }
-                // Video src hint must be provided, audio src hint is not used right now.
-                if (mSrcVideoFormatHint == null) {
-                    throw new UnsupportedOperationException(
-                            "Source video format hint must be set!");
-                }
-
-                boolean supportHevc = mClientCaps.isVideoMimeTypeSupported(
+                boolean supportHevc = getClientCapabilities().isVideoMimeTypeSupported(
                         MediaFormat.MIMETYPE_VIDEO_HEVC);
                 if (!supportHevc && MediaFormat.MIMETYPE_VIDEO_HEVC.equals(
                         mSrcVideoFormatHint.getString(MediaFormat.KEY_MIME))) {
@@ -910,13 +929,11 @@
 
             /**
              * Retrieves the video track format to be used on
-             * {@link Builder#setVideoTrackFormat(MediaFormat)} for this configuration.
+             * {@link VideoTranscodingRequest.Builder#setVideoTrackFormat(MediaFormat)} for this
+             * configuration.
              *
              * @return the video track format to be used if transcoding should be performed,
              *         and null otherwise.
-             * @throws UnsupportedOperationException
-             *         if {@link #setClientCapabilities(ApplicationMediaCapabilities)}
-             *         or {@link #setSourceVideoFormatHint(MediaFormat)} was not called.
              */
             @Nullable
             public MediaFormat resolveVideoFormat() {
@@ -1015,9 +1032,6 @@
              *
              * @return the audio track format to be used if transcoding should be performed, and
              *         null otherwise.
-             * @throws UnsupportedOperationException
-             *         if {@link #setClientCapabilities(ApplicationMediaCapabilities)}
-             *         or {@link #setSourceVideoFormatHint(MediaFormat)} was not called.
              * @hide
              */
             @Nullable
@@ -1366,21 +1380,6 @@
         public void setOnProgressUpdateListener(
                 @NonNull @CallbackExecutor Executor executor,
                 @Nullable OnProgressUpdateListener listener) {
-            setOnProgressUpdateListener(
-                    0 /* minProgressUpdateInterval */,
-                    executor, listener);
-        }
-
-        /**
-         * Set a progress listener with specified progress update interval.
-         * @param minProgressUpdateInterval The minimum interval between each progress update.
-         * @param executor The executor on which listener will be invoked.
-         * @param listener The progress listener.
-         */
-        public void setOnProgressUpdateListener(
-                int minProgressUpdateInterval,
-                @NonNull @CallbackExecutor Executor executor,
-                @Nullable OnProgressUpdateListener listener) {
             synchronized (mLock) {
                 Objects.requireNonNull(executor, "listenerExecutor must not be null");
                 Objects.requireNonNull(listener, "listener must not be null");
diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java
index f5bee6c..260c8a4 100644
--- a/cmds/sm/src/com/android/commands/sm/Sm.java
+++ b/cmds/sm/src/com/android/commands/sm/Sm.java
@@ -258,7 +258,7 @@
 
     public void runDisableAppDataIsolation() throws RemoteException {
         if (!SystemProperties.getBoolean(
-                ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, true)) {
+                ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false)) {
             throw new IllegalStateException("Storage app data isolation is not enabled.");
         }
         final String pkgName = nextArg();
diff --git a/core/api/current.txt b/core/api/current.txt
index 18c049f..5fcafc7 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -330,7 +330,7 @@
     field public static final int apiKey = 16843281; // 0x1010211
     field public static final int appCategory = 16844101; // 0x1010545
     field public static final int appComponentFactory = 16844154; // 0x101057a
-    field public static final int attributionTags = 16844353; // 0x1010641
+    field public static final int attributionTags = 16844354; // 0x1010642
     field public static final int author = 16843444; // 0x10102b4
     field public static final int authorities = 16842776; // 0x1010018
     field public static final int autoAdvanceViewId = 16843535; // 0x101030f
@@ -508,7 +508,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 = 16844349; // 0x101063d
+    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
@@ -530,8 +530,8 @@
     field public static final int detailSocialSummary = 16843428; // 0x10102a4
     field public static final int detailsElementBackground = 16843598; // 0x101034e
     field public static final int dial = 16843010; // 0x1010102
-    field public static final int dialTint = 16844341; // 0x1010635
-    field public static final int dialTintMode = 16844342; // 0x1010636
+    field public static final int dialTint = 16844342; // 0x1010636
+    field public static final int dialTintMode = 16844343; // 0x1010637
     field public static final int dialogCornerRadius = 16844145; // 0x1010571
     field public static final int dialogIcon = 16843252; // 0x10101f4
     field public static final int dialogLayout = 16843255; // 0x10101f7
@@ -729,14 +729,14 @@
     field public static final int groupIndicator = 16843019; // 0x101010b
     field public static final int gwpAsanMode = 16844310; // 0x1010616
     field public static final int hand_hour = 16843011; // 0x1010103
-    field public static final int hand_hourTint = 16844343; // 0x1010637
-    field public static final int hand_hourTintMode = 16844344; // 0x1010638
+    field public static final int hand_hourTint = 16844344; // 0x1010638
+    field public static final int hand_hourTintMode = 16844345; // 0x1010639
     field public static final int hand_minute = 16843012; // 0x1010104
-    field public static final int hand_minuteTint = 16844345; // 0x1010639
-    field public static final int hand_minuteTintMode = 16844346; // 0x101063a
+    field public static final int hand_minuteTint = 16844346; // 0x101063a
+    field public static final int hand_minuteTintMode = 16844347; // 0x101063b
     field public static final int hand_second = 16844323; // 0x1010623
-    field public static final int hand_secondTint = 16844347; // 0x101063b
-    field public static final int hand_secondTintMode = 16844348; // 0x101063c
+    field public static final int hand_secondTint = 16844348; // 0x101063c
+    field public static final int hand_secondTintMode = 16844349; // 0x101063d
     field public static final int handle = 16843354; // 0x101025a
     field public static final int handleProfiling = 16842786; // 0x1010022
     field public static final int hapticFeedbackEnabled = 16843358; // 0x101025e
@@ -820,7 +820,7 @@
     field public static final int installLocation = 16843447; // 0x10102b7
     field public static final int interactiveUiTimeout = 16844181; // 0x1010595
     field public static final int interpolator = 16843073; // 0x1010141
-    field public static final int isAccessibilityTool = 16844352; // 0x1010640
+    field public static final int isAccessibilityTool = 16844353; // 0x1010641
     field public static final int isAlwaysSyncable = 16843571; // 0x1010333
     field public static final int isAsciiCapable = 16843753; // 0x10103e9
     field public static final int isAuxiliary = 16843647; // 0x101037f
@@ -972,8 +972,8 @@
     field public static final int maxLines = 16843091; // 0x1010153
     field public static final int maxLongVersionCode = 16844163; // 0x1010583
     field public static final int maxRecents = 16843846; // 0x1010446
-    field public static final int maxResizeHeight = 16844338; // 0x1010632
-    field public static final int maxResizeWidth = 16844337; // 0x1010631
+    field public static final int maxResizeHeight = 16844339; // 0x1010633
+    field public static final int maxResizeWidth = 16844338; // 0x1010632
     field public static final int maxRows = 16843059; // 0x1010133
     field public static final int maxSdkVersion = 16843377; // 0x1010271
     field public static final int maxWidth = 16843039; // 0x101011f
@@ -1076,7 +1076,7 @@
     field public static final int panelTextAppearance = 16842850; // 0x1010062
     field public static final int parentActivityName = 16843687; // 0x10103a7
     field @Deprecated public static final int password = 16843100; // 0x101015c
-    field public static final int passwordsActivity = 16844350; // 0x101063e
+    field public static final int passwordsActivity = 16844351; // 0x101063f
     field public static final int path = 16842794; // 0x101002a
     field public static final int pathAdvancedPattern = 16844320; // 0x1010620
     field public static final int pathData = 16843781; // 0x1010405
@@ -1262,7 +1262,7 @@
     field public static final int segmentedButtonStyle = 16843568; // 0x1010330
     field public static final int selectAllOnFocus = 16843102; // 0x101015e
     field public static final int selectable = 16843238; // 0x10101e6
-    field public static final int selectableAsDefault = 16844351; // 0x101063f
+    field public static final int selectableAsDefault = 16844352; // 0x1010640
     field public static final int selectableItemBackground = 16843534; // 0x101030e
     field public static final int selectableItemBackgroundBorderless = 16843868; // 0x101045c
     field @Deprecated public static final int selectedDateVerticalBar = 16843591; // 0x1010347
@@ -1312,7 +1312,7 @@
     field public static final int spinnerMode = 16843505; // 0x10102f1
     field public static final int spinnerStyle = 16842881; // 0x1010081
     field public static final int spinnersShown = 16843595; // 0x101034b
-    field public static final int splashScreenTheme = 16844336; // 0x1010630
+    field public static final int splashScreenTheme = 16844337; // 0x1010631
     field public static final int splitMotionEvents = 16843503; // 0x10102ef
     field public static final int splitName = 16844105; // 0x1010549
     field public static final int splitTrack = 16843852; // 0x101044c
@@ -1395,7 +1395,7 @@
     field public static final int supportsRtl = 16843695; // 0x10103af
     field public static final int supportsSwitchingToNextInputMethod = 16843755; // 0x10103eb
     field public static final int supportsUploading = 16843419; // 0x101029b
-    field public static final int suppressesSpellChecker = 16844354; // 0x1010642
+    field public static final int suppressesSpellChecker = 16844355; // 0x1010643
     field public static final int switchMinWidth = 16843632; // 0x1010370
     field public static final int switchPadding = 16843633; // 0x1010371
     field public static final int switchPreferenceStyle = 16843629; // 0x101036d
@@ -1410,8 +1410,8 @@
     field public static final int tabWidgetStyle = 16842883; // 0x1010083
     field public static final int tag = 16842961; // 0x10100d1
     field public static final int targetActivity = 16843266; // 0x1010202
-    field public static final int targetCellHeight = 16844340; // 0x1010634
-    field public static final int targetCellWidth = 16844339; // 0x1010633
+    field public static final int targetCellHeight = 16844341; // 0x1010635
+    field public static final int targetCellWidth = 16844340; // 0x1010634
     field public static final int targetClass = 16842799; // 0x101002f
     field @Deprecated public static final int targetDescriptions = 16843680; // 0x10103a0
     field public static final int targetId = 16843740; // 0x10103dc
@@ -1680,7 +1680,8 @@
     field public static final int windowSplashScreenAnimationDuration = 16844334; // 0x101062e
     field public static final int windowSplashScreenBackground = 16844332; // 0x101062c
     field public static final int windowSplashScreenBrandingImage = 16844335; // 0x101062f
-    field public static final int windowSplashscreenContent = 16844132; // 0x1010564
+    field public static final int windowSplashScreenIconBackgroundColor = 16844336; // 0x1010630
+    field @Deprecated public static final int windowSplashscreenContent = 16844132; // 0x1010564
     field @Deprecated public static final int windowSwipeToDismiss = 16843763; // 0x10103f3
     field public static final int windowTitleBackgroundStyle = 16842844; // 0x101005c
     field public static final int windowTitleSize = 16842842; // 0x101005a
@@ -6137,13 +6138,13 @@
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.NotificationChannel> CREATOR;
     field public static final String DEFAULT_CHANNEL_ID = "miscellaneous";
-    field public static final String EDIT_CONVERSATION = "convo";
+    field public static final String EDIT_CONVERSATION = "conversation";
     field public static final String EDIT_IMPORTANCE = "importance";
     field public static final String EDIT_LAUNCHER = "launcher";
     field public static final String EDIT_LOCKED_DEVICE = "locked";
     field public static final String EDIT_SOUND = "sound";
     field public static final String EDIT_VIBRATION = "vibration";
-    field public static final String EDIT_ZEN = "dnd";
+    field public static final String EDIT_ZEN = "zen";
   }
 
   public final class NotificationChannelGroup implements android.os.Parcelable {
@@ -6942,6 +6943,7 @@
     method @Nullable public String onChoosePrivateKeyAlias(@NonNull android.content.Context, @NonNull android.content.Intent, int, @Nullable android.net.Uri, @Nullable String);
     method public void onNetworkLogsAvailable(@NonNull android.content.Context, @NonNull android.content.Intent, long, @IntRange(from=1) int);
     method public final void onReceive(@NonNull android.content.Context, @NonNull android.content.Intent);
+    method public void onSecurityLogsAvailable(@NonNull android.content.Context, @NonNull android.content.Intent);
   }
 
   public final class DeviceAdminInfo implements android.os.Parcelable {
@@ -7019,6 +7021,7 @@
     field public static final String ACTION_PASSWORD_FAILED = "android.app.action.ACTION_PASSWORD_FAILED";
     field public static final String ACTION_PASSWORD_SUCCEEDED = "android.app.action.ACTION_PASSWORD_SUCCEEDED";
     field public static final String ACTION_PROFILE_PROVISIONING_COMPLETE = "android.app.action.PROFILE_PROVISIONING_COMPLETE";
+    field public static final String ACTION_SECURITY_LOGS_AVAILABLE = "android.app.action.SECURITY_LOGS_AVAILABLE";
     field public static final int BUGREPORT_FAILURE_FAILED_COMPLETING = 0; // 0x0
     field public static final int BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE = 1; // 0x1
     field public static final String DEVICE_ADMIN_META_DATA = "android.app.device_admin";
@@ -7314,6 +7317,7 @@
     field public static final String DELEGATION_NETWORK_LOGGING = "delegation-network-logging";
     field public static final String DELEGATION_PACKAGE_ACCESS = "delegation-package-access";
     field public static final String DELEGATION_PERMISSION_GRANT = "delegation-permission-grant";
+    field public static final String DELEGATION_SECURITY_LOGGING = "delegation-security-logging";
     field public static final int ENCRYPTION_STATUS_ACTIVATING = 2; // 0x2
     field public static final int ENCRYPTION_STATUS_ACTIVE = 3; // 0x3
     field public static final int ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY = 4; // 0x4
@@ -8005,13 +8009,14 @@
     method public long getStartTimeMillis();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field public static final int ACTIVITY_ANNIVERSARY = 2; // 0x2
+    field public static final int ACTIVITY_AUDIO = 4; // 0x4
     field public static final int ACTIVITY_BIRTHDAY = 1; // 0x1
-    field public static final int ACTIVITY_GAME = 5; // 0x5
-    field public static final int ACTIVITY_LOCATION = 6; // 0x6
-    field public static final int ACTIVITY_MEDIA = 4; // 0x4
+    field public static final int ACTIVITY_GAME = 6; // 0x6
+    field public static final int ACTIVITY_LOCATION = 7; // 0x7
     field public static final int ACTIVITY_NEW_STORY = 3; // 0x3
     field public static final int ACTIVITY_OTHER = 0; // 0x0
-    field public static final int ACTIVITY_UPCOMING_BIRTHDAY = 7; // 0x7
+    field public static final int ACTIVITY_UPCOMING_BIRTHDAY = 8; // 0x8
+    field public static final int ACTIVITY_VIDEO = 5; // 0x5
     field public static final int AVAILABILITY_AVAILABLE = 0; // 0x0
     field public static final int AVAILABILITY_BUSY = 1; // 0x1
     field public static final int AVAILABILITY_OFFLINE = 2; // 0x2
@@ -18438,12 +18443,12 @@
   }
 
   public class MultiResolutionImageReader implements java.lang.AutoCloseable {
+    ctor public MultiResolutionImageReader(@NonNull java.util.Collection<android.hardware.camera2.params.MultiResolutionStreamInfo>, int, @IntRange(from=1) int);
     method public void close();
     method protected void finalize();
     method public void flush();
     method @NonNull public android.hardware.camera2.params.MultiResolutionStreamInfo getStreamInfoForImageReader(@NonNull android.media.ImageReader);
     method @NonNull public android.view.Surface getSurface();
-    method @NonNull public static android.hardware.camera2.MultiResolutionImageReader newInstance(@NonNull java.util.Collection<android.hardware.camera2.params.MultiResolutionStreamInfo>, int, @IntRange(from=1) int);
     method public void setOnImageAvailableListener(@Nullable android.media.ImageReader.OnImageAvailableListener, @Nullable java.util.concurrent.Executor);
   }
 
@@ -18554,10 +18559,10 @@
   }
 
   public class MultiResolutionStreamInfo {
-    ctor public MultiResolutionStreamInfo(int, int, @NonNull String);
-    method public int getHeight();
+    ctor public MultiResolutionStreamInfo(@IntRange(from=1) int, @IntRange(from=1) int, @NonNull String);
+    method @IntRange(from=1) public int getHeight();
     method @NonNull public String getPhysicalCameraId();
-    method public int getWidth();
+    method @IntRange(from=1) public int getWidth();
   }
 
   public final class OisSample {
@@ -20678,6 +20683,7 @@
     method public android.media.AudioDeviceInfo getPreferredDevice();
     method public android.media.AudioDeviceInfo getRoutedDevice();
     method public int getSampleRate();
+    method @IntRange(from=1) public int getStartThresholdInFrames();
     method public int getState();
     method public int getStreamType();
     method public boolean getTimestamp(android.media.AudioTimestamp);
@@ -20708,6 +20714,7 @@
     method public int setPositionNotificationPeriod(int);
     method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
     method public int setPresentation(@NonNull android.media.AudioPresentation);
+    method @IntRange(from=1) public int setStartThresholdInFrames(@IntRange(from=1) int);
     method @Deprecated protected void setState(int);
     method @Deprecated public int setStereoVolume(float, float);
     method public int setVolume(float);
@@ -26824,17 +26831,14 @@
   public final class VcnGatewayConnectionConfig {
     method @NonNull public int[] getExposedCapabilities();
     method @IntRange(from=android.net.vcn.VcnGatewayConnectionConfig.MIN_MTU_V6) public int getMaxMtu();
-    method @NonNull public int[] getRequiredUnderlyingCapabilities();
     method @NonNull public long[] getRetryInterval();
   }
 
   public static final class VcnGatewayConnectionConfig.Builder {
     ctor public VcnGatewayConnectionConfig.Builder(@NonNull android.net.vcn.VcnControlPlaneConfig);
     method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder addExposedCapability(int);
-    method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder addRequiredUnderlyingCapability(int);
     method @NonNull public android.net.vcn.VcnGatewayConnectionConfig build();
     method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder removeExposedCapability(int);
-    method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder removeRequiredUnderlyingCapability(int);
     method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setMaxMtu(@IntRange(from=android.net.vcn.VcnGatewayConnectionConfig.MIN_MTU_V6) int);
     method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setRetryInterval(@NonNull long[]);
   }
@@ -34831,6 +34835,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_MANAGE_MEDIA = "android.settings.REQUEST_MANAGE_MEDIA";
     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";
@@ -37401,12 +37406,15 @@
     method @NonNull public android.service.autofill.Dataset.Builder setAuthentication(@Nullable android.content.IntentSender);
     method @NonNull public android.service.autofill.Dataset.Builder setId(@Nullable String);
     method @NonNull public android.service.autofill.Dataset.Builder setInlinePresentation(@NonNull android.service.autofill.InlinePresentation);
+    method @NonNull public android.service.autofill.Dataset.Builder setInlinePresentation(@NonNull android.service.autofill.InlinePresentation, @NonNull android.service.autofill.InlinePresentation);
     method @NonNull public android.service.autofill.Dataset.Builder setValue(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue);
     method @NonNull public android.service.autofill.Dataset.Builder setValue(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @NonNull android.widget.RemoteViews);
     method @NonNull public android.service.autofill.Dataset.Builder setValue(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @Nullable java.util.regex.Pattern);
     method @NonNull public android.service.autofill.Dataset.Builder setValue(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @Nullable java.util.regex.Pattern, @NonNull android.widget.RemoteViews);
     method @NonNull public android.service.autofill.Dataset.Builder setValue(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @NonNull android.widget.RemoteViews, @NonNull android.service.autofill.InlinePresentation);
+    method @NonNull public android.service.autofill.Dataset.Builder setValue(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @NonNull android.widget.RemoteViews, @NonNull android.service.autofill.InlinePresentation, @NonNull android.service.autofill.InlinePresentation);
     method @NonNull public android.service.autofill.Dataset.Builder setValue(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @Nullable java.util.regex.Pattern, @NonNull android.widget.RemoteViews, @NonNull android.service.autofill.InlinePresentation);
+    method @NonNull public android.service.autofill.Dataset.Builder setValue(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @Nullable java.util.regex.Pattern, @NonNull android.widget.RemoteViews, @NonNull android.service.autofill.InlinePresentation, @NonNull android.service.autofill.InlinePresentation);
   }
 
   public final class DateTransformation implements android.os.Parcelable android.service.autofill.Transformation {
@@ -37507,6 +37515,7 @@
     method @NonNull public android.service.autofill.FillResponse.Builder disableAutofill(long);
     method @NonNull public android.service.autofill.FillResponse.Builder setAuthentication(@NonNull android.view.autofill.AutofillId[], @Nullable android.content.IntentSender, @Nullable android.widget.RemoteViews);
     method @NonNull public android.service.autofill.FillResponse.Builder setAuthentication(@NonNull android.view.autofill.AutofillId[], @Nullable android.content.IntentSender, @Nullable android.widget.RemoteViews, @Nullable android.service.autofill.InlinePresentation);
+    method @NonNull public android.service.autofill.FillResponse.Builder setAuthentication(@NonNull android.view.autofill.AutofillId[], @Nullable android.content.IntentSender, @Nullable android.widget.RemoteViews, @Nullable android.service.autofill.InlinePresentation, @Nullable android.service.autofill.InlinePresentation);
     method @NonNull public android.service.autofill.FillResponse.Builder setClientState(@Nullable android.os.Bundle);
     method @NonNull public android.service.autofill.FillResponse.Builder setFieldClassificationIds(@NonNull android.view.autofill.AutofillId...);
     method @NonNull public android.service.autofill.FillResponse.Builder setFlags(int);
@@ -37534,6 +37543,7 @@
 
   public final class InlinePresentation implements android.os.Parcelable {
     ctor public InlinePresentation(@NonNull android.app.slice.Slice, @NonNull android.widget.inline.InlinePresentationSpec, boolean);
+    method @NonNull public static android.service.autofill.InlinePresentation createTooltipPresentation(@NonNull android.app.slice.Slice, @NonNull android.widget.inline.InlinePresentationSpec);
     method public int describeContents();
     method @NonNull public android.widget.inline.InlinePresentationSpec getInlinePresentationSpec();
     method @NonNull public android.app.slice.Slice getSlice();
@@ -40314,7 +40324,6 @@
     method public static boolean isConfigForIdentifiedCarrier(android.os.PersistableBundle);
     method public void notifyConfigChangedForSubId(int);
     field public static final String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
-    field public static final int CARRIER_NR_AVAILABILITY_NONE = 0; // 0x0
     field public static final int CARRIER_NR_AVAILABILITY_NSA = 1; // 0x1
     field public static final int CARRIER_NR_AVAILABILITY_SA = 2; // 0x2
     field public static final int CROSS_SIM_SPN_FORMAT_CARRIER_NAME_ONLY = 0; // 0x0
@@ -40379,7 +40388,7 @@
     field public static final String KEY_CARRIER_INSTANT_LETTERING_LENGTH_LIMIT_INT = "carrier_instant_lettering_length_limit_int";
     field public static final String KEY_CARRIER_NAME_OVERRIDE_BOOL = "carrier_name_override_bool";
     field public static final String KEY_CARRIER_NAME_STRING = "carrier_name_string";
-    field public static final String KEY_CARRIER_NR_AVAILABILITY_INT = "carrier_nr_availability_int";
+    field public static final String KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY = "carrier_nr_availabilities_int_array";
     field public static final String KEY_CARRIER_PROVISIONS_WIFI_MERGED_NETWORKS_BOOL = "carrier_provisions_wifi_merged_networks_bool";
     field public static final String KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL = "carrier_rcs_provisioning_required_bool";
     field public static final String KEY_CARRIER_SETTINGS_ACTIVITY_COMPONENT_NAME_STRING = "carrier_settings_activity_component_name_string";
@@ -40624,7 +40633,10 @@
 
   public static final class CarrierConfigManager.ImsServiceEntitlement {
     field public static final String KEY_ENTITLEMENT_SERVER_URL_STRING = "imsserviceentitlement.entitlement_server_url_string";
+    field public static final String KEY_FCM_SENDER_ID_STRING = "imsserviceentitlement.fcm_sender_id_string";
+    field public static final String KEY_IMS_PROVISIONING_BOOL = "imsserviceentitlement.ims_provisioning_bool";
     field public static final String KEY_PREFIX = "imsserviceentitlement.";
+    field public static final String KEY_SHOW_VOWIFI_WEBVIEW_BOOL = "imsserviceentitlement.show_vowifi_webview_bool";
   }
 
   public static final class CarrierConfigManager.Iwlan {
@@ -41794,7 +41806,7 @@
     method @NonNull public android.os.Bundle getCarrierConfigValues();
     method @Deprecated public static android.telephony.SmsManager getDefault();
     method public static int getDefaultSmsSubscriptionId();
-    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getSmsCapacityOnIcc();
+    method @IntRange(from=0) @RequiresPermission(anyOf={android.Manifest.permission.READ_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE"}) public int getSmsCapacityOnIcc();
     method @Deprecated public static android.telephony.SmsManager getSmsManagerForSubscriptionId(int);
     method @RequiresPermission(android.Manifest.permission.SMS_FINANCIAL_TRANSACTIONS) public void getSmsMessagesForFinancialApp(android.os.Bundle, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.SmsManager.FinancialSmsCallback);
     method @Nullable @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getSmscAddress();
@@ -51336,6 +51348,7 @@
     method @NonNull public android.os.Bundle getExtras();
     method @NonNull public String getHostPackageName();
     method @NonNull public java.util.List<android.widget.inline.InlinePresentationSpec> getInlinePresentationSpecs();
+    method @Nullable public android.widget.inline.InlinePresentationSpec getInlineTooltipPresentationSpec();
     method public int getMaxSuggestionCount();
     method @NonNull public android.os.LocaleList getSupportedLocales();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -51347,9 +51360,12 @@
     ctor public InlineSuggestionsRequest.Builder(@NonNull java.util.List<android.widget.inline.InlinePresentationSpec>);
     method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder addInlinePresentationSpecs(@NonNull android.widget.inline.InlinePresentationSpec);
     method @NonNull public android.view.inputmethod.InlineSuggestionsRequest build();
+    method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setClientSupported(boolean);
     method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setExtras(@NonNull android.os.Bundle);
     method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(@NonNull java.util.List<android.widget.inline.InlinePresentationSpec>);
+    method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setInlineTooltipPresentationSpec(@NonNull android.widget.inline.InlinePresentationSpec);
     method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setMaxSuggestionCount(int);
+    method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setServiceSupported(boolean);
     method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setSupportedLocales(@NonNull android.os.LocaleList);
   }
 
@@ -52306,10 +52322,10 @@
 
   public final class TextServicesManager {
     method @Nullable public android.view.textservice.SpellCheckerInfo getCurrentSpellCheckerInfo();
-    method @Nullable public java.util.List<android.view.textservice.SpellCheckerInfo> getEnabledSpellCheckerInfos();
+    method @NonNull public java.util.List<android.view.textservice.SpellCheckerInfo> getEnabledSpellCheckerInfos();
     method public boolean isSpellCheckerEnabled();
     method @Nullable public android.view.textservice.SpellCheckerSession newSpellCheckerSession(@Nullable android.os.Bundle, @Nullable java.util.Locale, @NonNull android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener, boolean);
-    method @Nullable public android.view.textservice.SpellCheckerSession newSpellCheckerSession(@Nullable android.os.Bundle, @Nullable java.util.Locale, @NonNull android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener, boolean, int);
+    method @Nullable public android.view.textservice.SpellCheckerSession newSpellCheckerSession(@Nullable java.util.Locale, boolean, int, @Nullable android.os.Bundle, @NonNull java.util.concurrent.Executor, @NonNull android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener);
   }
 
 }
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 51b6967..e3b7c88 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -61,6 +61,7 @@
 
   public abstract class Context {
     method @NonNull public android.os.UserHandle getUser();
+    field public static final String TEST_NETWORK_SERVICE = "test_network";
   }
 
   public class Intent implements java.lang.Cloneable android.os.Parcelable {
@@ -191,6 +192,29 @@
     method public int getResourceId();
   }
 
+  public class NetworkPolicyManager {
+    method @NonNull public static String blockedReasonsToString(int);
+    method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public int getMultipathPreference(@NonNull android.net.Network);
+    method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public int getRestrictBackgroundStatus(int);
+    method public static boolean isUidBlocked(int, boolean);
+    method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidNetworkingBlocked(int, boolean);
+    method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidRestrictedOnMeteredNetworks(int);
+    method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void registerNetworkPolicyCallback(@Nullable java.util.concurrent.Executor, @NonNull android.net.NetworkPolicyManager.NetworkPolicyCallback);
+    method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void unregisterNetworkPolicyCallback(@NonNull android.net.NetworkPolicyManager.NetworkPolicyCallback);
+    field public static final int BLOCKED_METERED_REASON_ADMIN_DISABLED = 262144; // 0x40000
+    field public static final int BLOCKED_METERED_REASON_DATA_SAVER = 65536; // 0x10000
+    field public static final int BLOCKED_METERED_REASON_USER_RESTRICTED = 131072; // 0x20000
+    field public static final int BLOCKED_REASON_APP_STANDBY = 4; // 0x4
+    field public static final int BLOCKED_REASON_BATTERY_SAVER = 1; // 0x1
+    field public static final int BLOCKED_REASON_DOZE = 2; // 0x2
+    field public static final int BLOCKED_REASON_NONE = 0; // 0x0
+    field public static final int BLOCKED_REASON_RESTRICTED_MODE = 8; // 0x8
+  }
+
+  public static interface NetworkPolicyManager.NetworkPolicyCallback {
+    method public default void onUidBlockedReasonChanged(int, int);
+  }
+
   public final class NetworkStateSnapshot implements android.os.Parcelable {
     ctor public NetworkStateSnapshot(@NonNull android.net.Network, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, @Nullable String, int);
     method public int describeContents();
@@ -234,6 +258,7 @@
   public class VpnManager {
     field @Deprecated public static final int TYPE_VPN_LEGACY = 3; // 0x3
     field public static final int TYPE_VPN_NONE = -1; // 0xffffffff
+    field public static final int TYPE_VPN_OEM = 4; // 0x4
     field public static final int TYPE_VPN_PLATFORM = 2; // 0x2
     field public static final int TYPE_VPN_SERVICE = 1; // 0x1
   }
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 2a99aaa..8237f12 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -126,6 +126,7 @@
     field public static final String MANAGE_ACCESSIBILITY = "android.permission.MANAGE_ACCESSIBILITY";
     field @Deprecated public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
     field public static final String MANAGE_ACTIVITY_TASKS = "android.permission.MANAGE_ACTIVITY_TASKS";
+    field public static final String MANAGE_APP_HIBERNATION = "android.permission.MANAGE_APP_HIBERNATION";
     field public static final String MANAGE_APP_OPS_RESTRICTIONS = "android.permission.MANAGE_APP_OPS_RESTRICTIONS";
     field public static final String MANAGE_APP_PREDICTIONS = "android.permission.MANAGE_APP_PREDICTIONS";
     field public static final String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS";
@@ -136,6 +137,7 @@
     field public static final String MANAGE_CONTENT_SUGGESTIONS = "android.permission.MANAGE_CONTENT_SUGGESTIONS";
     field public static final String MANAGE_DEBUGGING = "android.permission.MANAGE_DEBUGGING";
     field public static final String MANAGE_FACTORY_RESET_PROTECTION = "android.permission.MANAGE_FACTORY_RESET_PROTECTION";
+    field public static final String MANAGE_HOTWORD_DETECTION = "android.permission.MANAGE_HOTWORD_DETECTION";
     field public static final String MANAGE_IPSEC_TUNNELS = "android.permission.MANAGE_IPSEC_TUNNELS";
     field public static final String MANAGE_MUSIC_RECOGNITION = "android.permission.MANAGE_MUSIC_RECOGNITION";
     field public static final String MANAGE_NOTIFICATION_LISTENERS = "android.permission.MANAGE_NOTIFICATION_LISTENERS";
@@ -201,7 +203,6 @@
     field public static final String READ_DEVICE_CONFIG = "android.permission.READ_DEVICE_CONFIG";
     field public static final String READ_DREAM_STATE = "android.permission.READ_DREAM_STATE";
     field public static final String READ_INSTALL_SESSIONS = "android.permission.READ_INSTALL_SESSIONS";
-    field public static final String READ_NETWORK_DEVICE_CONFIG = "android.permission.READ_NETWORK_DEVICE_CONFIG";
     field public static final String READ_NETWORK_USAGE_HISTORY = "android.permission.READ_NETWORK_USAGE_HISTORY";
     field public static final String READ_OEM_UNLOCK_STATE = "android.permission.READ_OEM_UNLOCK_STATE";
     field public static final String READ_PEOPLE_DATA = "android.permission.READ_PEOPLE_DATA";
@@ -407,7 +408,7 @@
     method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public static void setPersistentVrThread(int);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public boolean startProfile(@NonNull android.os.UserHandle);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public boolean stopProfile(@NonNull android.os.UserHandle);
-    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean switchUser(@NonNull android.os.UserHandle);
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean switchUser(@NonNull android.os.UserHandle);
   }
 
   public static interface ActivityManager.OnUidImportanceListener {
@@ -910,7 +911,6 @@
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioned();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioningConfigApplied();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isManagedKiosk();
-    method public boolean isNetworkSlicingEnabledForUser(@NonNull android.os.UserHandle);
     method public boolean isSecondaryLockscreenEnabled(@NonNull android.os.UserHandle);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isUnattendedManagedKiosk();
     method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long);
@@ -1695,6 +1695,13 @@
 
 package android.app.time {
 
+  public final class Capabilities {
+    field public static final int CAPABILITY_NOT_ALLOWED = 20; // 0x14
+    field public static final int CAPABILITY_NOT_APPLICABLE = 30; // 0x1e
+    field public static final int CAPABILITY_NOT_SUPPORTED = 10; // 0xa
+    field public static final int CAPABILITY_POSSESSED = 40; // 0x28
+  }
+
   public final class TimeManager {
     method @RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION) public void addTimeZoneDetectorListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.time.TimeManager.TimeZoneDetectorListener);
     method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION) public android.app.time.TimeZoneCapabilitiesAndConfig getTimeZoneCapabilitiesAndConfig();
@@ -1711,10 +1718,6 @@
     method public int getConfigureAutoDetectionEnabledCapability();
     method public int getConfigureGeoDetectionEnabledCapability();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field public static final int CAPABILITY_NOT_ALLOWED = 20; // 0x14
-    field public static final int CAPABILITY_NOT_APPLICABLE = 30; // 0x1e
-    field public static final int CAPABILITY_NOT_SUPPORTED = 10; // 0xa
-    field public static final int CAPABILITY_POSSESSED = 40; // 0x28
     field @NonNull public static final android.os.Parcelable.Creator<android.app.time.TimeZoneCapabilities> CREATOR;
   }
 
@@ -1829,10 +1832,10 @@
 package android.apphibernation {
 
   public final class AppHibernationManager {
-    method public boolean isHibernatingForUser(@NonNull String);
-    method public boolean isHibernatingGlobally(@NonNull String);
-    method public void setHibernatingForUser(@NonNull String, boolean);
-    method public void setHibernatingGlobally(@NonNull String, boolean);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION) public boolean isHibernatingForUser(@NonNull String);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION) public boolean isHibernatingGlobally(@NonNull String);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION) public void setHibernatingForUser(@NonNull String, boolean);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION) public void setHibernatingGlobally(@NonNull String, boolean);
   }
 
 }
@@ -3656,7 +3659,6 @@
     field public static final int RESULT_FAILED_BAD_PARAMS = 2; // 0x2
     field public static final int RESULT_FAILED_BUSY = 4; // 0x4
     field public static final int RESULT_FAILED_HAL_UNAVAILABLE = 8; // 0x8
-    field public static final int RESULT_FAILED_PERMISSION_DENIED = 9; // 0x9
     field public static final int RESULT_FAILED_SERVICE_INTERNAL_FAILURE = 7; // 0x7
     field public static final int RESULT_FAILED_TIMEOUT = 6; // 0x6
     field public static final int RESULT_FAILED_UNINITIALIZED = 3; // 0x3
@@ -5058,8 +5060,8 @@
     method @IntRange(from=0) public long getAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo);
     method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioProductStrategy> getAudioProductStrategies();
     method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioVolumeGroup> getAudioVolumeGroups();
-    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes);
-    method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getDevicesForAttributes(@NonNull android.media.AudioAttributes);
+    method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, "android.permission.QUERY_AUDIO_STATE"}) public int getDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes);
+    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, "android.permission.QUERY_AUDIO_STATE"}) public java.util.List<android.media.AudioDeviceAttributes> getDevicesForAttributes(@NonNull android.media.AudioAttributes);
     method @IntRange(from=0) public long getMaxAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo);
     method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
     method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMinVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
@@ -10340,6 +10342,32 @@
     method public int getStart();
   }
 
+  public final class HotwordDetectedResult implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getByteOffset();
+    method public int getConfidenceLevel();
+    method @NonNull public android.os.Bundle getExtras();
+    method @Nullable public String getHotwordPhrase();
+    method public static int getMaxBundleSize();
+    method public static int getMaxScore();
+    method public int getPersonalizedScore();
+    method public int getScore();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int BYTE_OFFSET_UNSET = -1; // 0xffffffff
+    field @NonNull public static final android.os.Parcelable.Creator<android.service.voice.HotwordDetectedResult> CREATOR;
+  }
+
+  public static final class HotwordDetectedResult.Builder {
+    ctor public HotwordDetectedResult.Builder();
+    method @NonNull public android.service.voice.HotwordDetectedResult build();
+    method @NonNull public android.service.voice.HotwordDetectedResult.Builder setByteOffset(int);
+    method @NonNull public android.service.voice.HotwordDetectedResult.Builder setConfidenceLevel(int);
+    method @NonNull public android.service.voice.HotwordDetectedResult.Builder setExtras(@NonNull android.os.Bundle);
+    method @NonNull public android.service.voice.HotwordDetectedResult.Builder setHotwordPhrase(@NonNull String);
+    method @NonNull public android.service.voice.HotwordDetectedResult.Builder setPersonalizedScore(int);
+    method @NonNull public android.service.voice.HotwordDetectedResult.Builder setScore(int);
+  }
+
   public abstract class HotwordDetectionService extends android.app.Service {
     ctor public HotwordDetectionService();
     method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
@@ -10353,9 +10381,23 @@
     method public void onRejected();
   }
 
+  public interface HotwordDetector {
+    field public static final int CONFIDENCE_LEVEL_HIGH = 3; // 0x3
+    field public static final int CONFIDENCE_LEVEL_LOW = 1; // 0x1
+    field public static final int CONFIDENCE_LEVEL_MEDIUM = 2; // 0x2
+    field public static final int CONFIDENCE_LEVEL_NONE = 0; // 0x0
+  }
+
+  public final class HotwordRejectedResult implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getConfidenceLevel();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.service.voice.HotwordRejectedResult> CREATOR;
+  }
+
   public class VoiceInteractionService extends android.app.Service {
     method @NonNull public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(String, java.util.Locale, android.service.voice.AlwaysOnHotwordDetector.Callback);
-    method @NonNull public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(String, java.util.Locale, @Nullable android.os.Bundle, @Nullable android.os.SharedMemory, android.service.voice.AlwaysOnHotwordDetector.Callback);
+    method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(String, java.util.Locale, @Nullable android.os.Bundle, @Nullable android.os.SharedMemory, android.service.voice.AlwaysOnHotwordDetector.Callback);
     method @NonNull @RequiresPermission("android.permission.MANAGE_VOICE_KEYPHRASES") public final android.media.voice.KeyphraseModelManager createKeyphraseModelManager();
   }
 
@@ -12041,7 +12083,7 @@
     method public int getPduSessionId();
     method public int getProtocolType();
     method public long getRetryDurationMillis();
-    method @Nullable public android.telephony.data.SliceInfo getSliceInfo();
+    method @Nullable public android.telephony.data.NetworkSliceInfo getSliceInfo();
     method @Deprecated public int getSuggestedRetryTime();
     method @NonNull public java.util.List<android.telephony.data.TrafficDescriptor> getTrafficDescriptors();
     method public void writeToParcel(android.os.Parcel, int);
@@ -12077,7 +12119,7 @@
     method @NonNull public android.telephony.data.DataCallResponse.Builder setPduSessionId(@IntRange(from=android.telephony.data.DataCallResponse.PDU_SESSION_ID_NOT_SET, to=15) int);
     method @NonNull public android.telephony.data.DataCallResponse.Builder setProtocolType(int);
     method @NonNull public android.telephony.data.DataCallResponse.Builder setRetryDurationMillis(long);
-    method @NonNull public android.telephony.data.DataCallResponse.Builder setSliceInfo(@Nullable android.telephony.data.SliceInfo);
+    method @NonNull public android.telephony.data.DataCallResponse.Builder setSliceInfo(@Nullable android.telephony.data.NetworkSliceInfo);
     method @Deprecated @NonNull public android.telephony.data.DataCallResponse.Builder setSuggestedRetryTime(int);
     method @NonNull public android.telephony.data.DataCallResponse.Builder setTrafficDescriptors(@NonNull java.util.List<android.telephony.data.TrafficDescriptor>);
   }
@@ -12150,7 +12192,7 @@
     method public void setDataProfile(@NonNull java.util.List<android.telephony.data.DataProfile>, boolean, @NonNull android.telephony.data.DataServiceCallback);
     method public void setInitialAttachApn(@NonNull android.telephony.data.DataProfile, boolean, @NonNull android.telephony.data.DataServiceCallback);
     method public void setupDataCall(int, @NonNull android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @NonNull android.telephony.data.DataServiceCallback);
-    method public void setupDataCall(int, @NonNull android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @IntRange(from=0, to=15) int, @Nullable android.telephony.data.SliceInfo, @Nullable android.telephony.data.TrafficDescriptor, boolean, @NonNull android.telephony.data.DataServiceCallback);
+    method public void setupDataCall(int, @NonNull android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @IntRange(from=0, to=15) int, @Nullable android.telephony.data.NetworkSliceInfo, @Nullable android.telephony.data.TrafficDescriptor, boolean, @NonNull android.telephony.data.DataServiceCallback);
   }
 
   public class DataServiceCallback {
@@ -12180,6 +12222,32 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.EpsBearerQosSessionAttributes> CREATOR;
   }
 
+  public final class NetworkSliceInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method @IntRange(from=android.telephony.data.NetworkSliceInfo.MIN_SLICE_DIFFERENTIATOR, to=android.telephony.data.NetworkSliceInfo.MAX_SLICE_DIFFERENTIATOR) public int getMappedHplmnSliceDifferentiator();
+    method public int getMappedHplmnSliceServiceType();
+    method @IntRange(from=android.telephony.data.NetworkSliceInfo.MIN_SLICE_DIFFERENTIATOR, to=android.telephony.data.NetworkSliceInfo.MAX_SLICE_DIFFERENTIATOR) public int getSliceDifferentiator();
+    method public int getSliceServiceType();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.NetworkSliceInfo> CREATOR;
+    field public static final int MAX_SLICE_DIFFERENTIATOR = 16777214; // 0xfffffe
+    field public static final int MIN_SLICE_DIFFERENTIATOR = -1; // 0xffffffff
+    field public static final int SLICE_DIFFERENTIATOR_NO_SLICE = -1; // 0xffffffff
+    field public static final int SLICE_SERVICE_TYPE_EMBB = 1; // 0x1
+    field public static final int SLICE_SERVICE_TYPE_MIOT = 3; // 0x3
+    field public static final int SLICE_SERVICE_TYPE_NONE = 0; // 0x0
+    field public static final int SLICE_SERVICE_TYPE_URLLC = 2; // 0x2
+  }
+
+  public static final class NetworkSliceInfo.Builder {
+    ctor public NetworkSliceInfo.Builder();
+    method @NonNull public android.telephony.data.NetworkSliceInfo build();
+    method @NonNull public android.telephony.data.NetworkSliceInfo.Builder setMappedHplmnSliceDifferentiator(@IntRange(from=android.telephony.data.NetworkSliceInfo.MIN_SLICE_DIFFERENTIATOR, to=android.telephony.data.NetworkSliceInfo.MAX_SLICE_DIFFERENTIATOR) int);
+    method @NonNull public android.telephony.data.NetworkSliceInfo.Builder setMappedHplmnSliceServiceType(int);
+    method @NonNull public android.telephony.data.NetworkSliceInfo.Builder setSliceDifferentiator(@IntRange(from=android.telephony.data.NetworkSliceInfo.MIN_SLICE_DIFFERENTIATOR, to=android.telephony.data.NetworkSliceInfo.MAX_SLICE_DIFFERENTIATOR) int);
+    method @NonNull public android.telephony.data.NetworkSliceInfo.Builder setSliceServiceType(int);
+  }
+
   public abstract class QualifiedNetworksService extends android.app.Service {
     ctor public QualifiedNetworksService();
     method @NonNull public abstract android.telephony.data.QualifiedNetworksService.NetworkAvailabilityProvider onCreateNetworkAvailabilityProvider(int);
@@ -12194,32 +12262,6 @@
     method public final void updateQualifiedNetworkTypes(int, @NonNull java.util.List<java.lang.Integer>);
   }
 
-  public final class SliceInfo implements android.os.Parcelable {
-    method public int describeContents();
-    method @IntRange(from=android.telephony.data.SliceInfo.MIN_SLICE_DIFFERENTIATOR, to=android.telephony.data.SliceInfo.MAX_SLICE_DIFFERENTIATOR) public int getMappedHplmnSliceDifferentiator();
-    method public int getMappedHplmnSliceServiceType();
-    method @IntRange(from=android.telephony.data.SliceInfo.MIN_SLICE_DIFFERENTIATOR, to=android.telephony.data.SliceInfo.MAX_SLICE_DIFFERENTIATOR) public int getSliceDifferentiator();
-    method public int getSliceServiceType();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.SliceInfo> CREATOR;
-    field public static final int MAX_SLICE_DIFFERENTIATOR = 16777214; // 0xfffffe
-    field public static final int MIN_SLICE_DIFFERENTIATOR = -1; // 0xffffffff
-    field public static final int SLICE_DIFFERENTIATOR_NO_SLICE = -1; // 0xffffffff
-    field public static final int SLICE_SERVICE_TYPE_EMBB = 1; // 0x1
-    field public static final int SLICE_SERVICE_TYPE_MIOT = 3; // 0x3
-    field public static final int SLICE_SERVICE_TYPE_NONE = 0; // 0x0
-    field public static final int SLICE_SERVICE_TYPE_URLLC = 2; // 0x2
-  }
-
-  public static final class SliceInfo.Builder {
-    ctor public SliceInfo.Builder();
-    method @NonNull public android.telephony.data.SliceInfo build();
-    method @NonNull public android.telephony.data.SliceInfo.Builder setMappedHplmnSliceDifferentiator(@IntRange(from=android.telephony.data.SliceInfo.MIN_SLICE_DIFFERENTIATOR, to=android.telephony.data.SliceInfo.MAX_SLICE_DIFFERENTIATOR) int);
-    method @NonNull public android.telephony.data.SliceInfo.Builder setMappedHplmnSliceServiceType(int);
-    method @NonNull public android.telephony.data.SliceInfo.Builder setSliceDifferentiator(@IntRange(from=android.telephony.data.SliceInfo.MIN_SLICE_DIFFERENTIATOR, to=android.telephony.data.SliceInfo.MAX_SLICE_DIFFERENTIATOR) int);
-    method @NonNull public android.telephony.data.SliceInfo.Builder setSliceServiceType(int);
-  }
-
   public final class ThrottleStatus implements android.os.Parcelable {
     method public int describeContents();
     method public int getApnType();
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index e486fa2..4be6206 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -104,7 +104,9 @@
     method @RequiresPermission(android.Manifest.permission.RESET_APP_ERRORS) public void resetAppErrors();
     method public static void resumeAppSwitches() throws android.os.RemoteException;
     method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public void scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int);
+    method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public boolean stopUser(int, boolean);
     method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public boolean updateMccMncConfiguration(@NonNull String, @NonNull String);
+    method @RequiresPermission(android.Manifest.permission.DUMP) public void waitForBroadcastIdle();
     field public static final long DROP_CLOSE_SYSTEM_DIALOGS = 174664120L; // 0xa6929b8L
     field public static final long LOCK_DOWN_CLOSE_SYSTEM_DIALOGS = 174664365L; // 0xa692aadL
     field public static final int PROCESS_CAPABILITY_ALL = 15; // 0xf
@@ -427,6 +429,7 @@
     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 String ACTION_DEVICE_POLICY_CONSTANTS_CHANGED = "android.app.action.DEVICE_POLICY_CONSTANTS_CHANGED";
     field public static final int CODE_ACCOUNTS_NOT_EMPTY = 6; // 0x6
     field public static final int CODE_CANNOT_ADD_MANAGED_PROFILE = 11; // 0xb
     field public static final int CODE_DEVICE_ADMIN_NOT_SUPPORTED = 13; // 0xd
@@ -709,6 +712,10 @@
     method public int getDisplayId();
   }
 
+  public class Intent implements java.lang.Cloneable android.os.Parcelable {
+    field public static final String ACTION_USER_STOPPED = "android.intent.action.USER_STOPPED";
+  }
+
   public class SyncAdapterType implements android.os.Parcelable {
     method @Nullable public String getPackageName();
   }
@@ -1026,6 +1033,16 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public String getUiPackage();
   }
 
+  public class BiometricPrompt {
+    method @NonNull public java.util.List<java.lang.Integer> getAllowedSensorIds();
+    method public boolean isAllowBackgroundAuthentication();
+  }
+
+  public static class BiometricPrompt.Builder {
+    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.TEST_BIOMETRIC, "android.permission.USE_BIOMETRIC_INTERNAL"}) public android.hardware.biometrics.BiometricPrompt.Builder setAllowBackgroundAuthentication(boolean);
+    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.TEST_BIOMETRIC, "android.permission.USE_BIOMETRIC_INTERNAL"}) public android.hardware.biometrics.BiometricPrompt.Builder setAllowedSensorIds(@NonNull java.util.List<java.lang.Integer>);
+  }
+
   public class BiometricTestSession implements java.lang.AutoCloseable {
     method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void acceptAuthentication(int);
     method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void cleanupInternalState(int);
@@ -1038,6 +1055,7 @@
   }
 
   public class SensorProperties {
+    method @NonNull public java.util.List<android.hardware.biometrics.SensorProperties.ComponentInfo> getComponentInfo();
     method public int getSensorId();
     method public int getSensorStrength();
     field public static final int STRENGTH_CONVENIENCE = 0; // 0x0
@@ -1045,6 +1063,14 @@
     field public static final int STRENGTH_WEAK = 1; // 0x1
   }
 
+  public static final class SensorProperties.ComponentInfo {
+    method @NonNull public String getComponentId();
+    method @NonNull public String getFirmwareVersion();
+    method @NonNull public String getHardwareVersion();
+    method @NonNull public String getSerialNumber();
+    method @NonNull public String getSoftwareVersion();
+  }
+
 }
 
 package android.hardware.camera2 {
@@ -1329,6 +1355,7 @@
   public class AudioManager {
     method @Nullable public static android.media.AudioDeviceInfo getDeviceInfoFromType(int);
     method public boolean hasRegisteredDynamicPolicy();
+    method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, android.Manifest.permission.QUERY_AUDIO_STATE}) public boolean isFullVolumeDevice();
   }
 
   public static final class AudioRecord.MetricsConstants {
@@ -1480,6 +1507,8 @@
 
   public class NetworkPolicyManager {
     method public boolean getRestrictBackground();
+    method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidNetworkingBlocked(int, boolean);
+    method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidRestrictedOnMeteredNetworks(int);
     method @NonNull public static String resolveNetworkId(@NonNull android.net.wifi.WifiConfiguration);
     method public void setRestrictBackground(boolean);
   }
@@ -2902,6 +2931,7 @@
 
   public final class SplashScreenView extends android.widget.FrameLayout {
     method @Nullable public android.view.View getBrandingView();
+    method @ColorInt public int getIconBackgroundColor();
   }
 
   public final class StartingWindowInfo implements android.os.Parcelable {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index f5f0b42..86e2723 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1628,6 +1628,18 @@
     }
 
     /**
+     * Clear the splash screen view if exist.
+     * @hide
+     */
+    public void detachSplashScreenView() {
+        synchronized (this) {
+            if (mSplashScreenView != null) {
+                mSplashScreenView = null;
+            }
+        }
+    }
+
+    /**
      * Same as {@link #onCreate(android.os.Bundle)} but called for those activities created with
      * the attribute {@link android.R.attr#persistableMode} set to
      * <code>persistAcrossReboots</code>.
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index f905ec8..3fedda3 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -31,6 +31,7 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
+import android.annotation.UserIdInt;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledSince;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -4048,7 +4049,8 @@
      * @hide
      */
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.CREATE_USERS})
     public boolean switchUser(@NonNull UserHandle user) {
         if (user == null) {
             throw new IllegalArgumentException("UserHandle cannot be null.");
@@ -4144,6 +4146,25 @@
         }
     }
 
+    /**
+     * Stops the given {@code userId}.
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+    public boolean stopUser(@UserIdInt int userId, boolean force) {
+        if (userId == UserHandle.USER_SYSTEM) {
+            return false;
+        }
+        try {
+            return USER_OP_SUCCESS == getService().stopUser(
+                    userId, force, /* callback= */ null);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     /** {@hide} */
     public static final int FLAG_OR_STOPPED = 1 << 0;
     /** {@hide} */
@@ -4811,6 +4832,21 @@
     }
 
     /**
+     * Blocks until all broadcast queues become idle.
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.DUMP)
+    public void waitForBroadcastIdle() {
+        try {
+            getService().waitForBroadcastIdle();
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * A subset of immutable pending intent information suitable for caching on the client side.
      *
      * @hide
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index c812e8e..f7a3514 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -450,6 +450,21 @@
     public abstract boolean hasRunningForegroundService(int uid, int foregroundServiceType);
 
     /**
+     * Returns {@code true} if the given notification channel currently has a
+     * notification associated with a foreground service.  This is an AMS check
+     * because that is the source of truth for the FGS state.
+     */
+    public abstract boolean hasForegroundServiceNotification(String pkg, @UserIdInt int userId,
+            String channelId);
+
+    /**
+     * If the given app has any FGSs whose notifications are in the given channel,
+     * stop them.
+     */
+    public abstract void stopForegroundServicesForChannel(String pkg, @UserIdInt int userId,
+            String channelId);
+
+    /**
      * Registers the specified {@code processObserver} to be notified of future changes to
      * process state.
      */
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 837154f..c1d8541 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -292,7 +292,6 @@
     /** Use background GC policy and default JIT threshold. */
     private static final int VM_PROCESS_STATE_JANK_IMPERCEPTIBLE = 1;
 
-    private static final int REMOVE_SPLASH_SCREEN_VIEW_TIMEOUT = 5000;
     /**
      * Denotes an invalid sequence number corresponding to a process state change.
      */
@@ -1956,8 +1955,6 @@
         public static final int INSTRUMENT_WITHOUT_RESTART = 170;
         public static final int FINISH_INSTRUMENTATION_WITHOUT_RESTART = 171;
 
-        public static final int REMOVE_SPLASH_SCREEN_VIEW = 172;
-
         String codeToString(int code) {
             if (DEBUG_MESSAGES) {
                 switch (code) {
@@ -2006,8 +2003,6 @@
                     case INSTRUMENT_WITHOUT_RESTART: return "INSTRUMENT_WITHOUT_RESTART";
                     case FINISH_INSTRUMENTATION_WITHOUT_RESTART:
                         return "FINISH_INSTRUMENTATION_WITHOUT_RESTART";
-                    case REMOVE_SPLASH_SCREEN_VIEW:
-                        return "REMOVE_SPLASH_SCREEN_VIEW";
                 }
             }
             return Integer.toString(code);
@@ -2204,9 +2199,6 @@
                 case FINISH_INSTRUMENTATION_WITHOUT_RESTART:
                     handleFinishInstrumentationWithoutRestart();
                     break;
-                case REMOVE_SPLASH_SCREEN_VIEW:
-                    handleRemoveSplashScreenView((ActivityClientRecord) msg.obj);
-                    break;
             }
             Object obj = msg.obj;
             if (obj instanceof SomeArgs) {
@@ -4020,6 +4012,7 @@
         view.cacheRootWindow(r.window);
         view.makeSystemUIColorsTransparent();
         r.activity.mSplashScreenView = view;
+        view.attachHostActivity(r.activity);
         view.requestLayout();
         // Ensure splash screen view is shown before remove the splash screen window.
         final ViewRootImpl impl = decorView.getViewRootImpl();
@@ -4062,8 +4055,6 @@
     @Override
     public void handOverSplashScreenView(@NonNull ActivityClientRecord r) {
         if (r.activity.mSplashScreenView != null) {
-            Message msg = mH.obtainMessage(H.REMOVE_SPLASH_SCREEN_VIEW, r);
-            mH.sendMessageDelayed(msg, REMOVE_SPLASH_SCREEN_VIEW_TIMEOUT);
             synchronized (this) {
                 if (mSplashScreenGlobal != null) {
                     mSplashScreenGlobal.dispatchOnExitAnimation(r.token,
@@ -4074,16 +4065,6 @@
     }
 
     /**
-     * Force remove splash screen view.
-     */
-    private void handleRemoveSplashScreenView(@NonNull ActivityClientRecord r) {
-        if (r.activity.mSplashScreenView != null) {
-            r.activity.mSplashScreenView.remove();
-            r.activity.mSplashScreenView = null;
-        }
-    }
-
-    /**
      * Cycle activity through onPause and onUserLeaveHint so that PIP is entered if supported, then
      * return to its previous state. This allows activities that rely on onUserLeaveHint instead of
      * onPictureInPictureRequested to enter picture-in-picture.
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index ef0dcab..4c2433c 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -709,4 +709,7 @@
     ParceledListSlice queryIntentComponentsForIntentSender(in IIntentSender sender, int matchFlags);
 
     int getUidProcessCapabilities(int uid, in String callingPackage);
+
+    /** Blocks until all broadcast queues become idle. */
+    void waitForBroadcastIdle();
 }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index a3a8a5e..60506b5 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -823,6 +823,17 @@
     public static final int VISIBILITY_SECRET = -1;
 
     /**
+     * @hide
+     */
+    @IntDef(prefix = "VISIBILITY_", value = {
+            VISIBILITY_PUBLIC,
+            VISIBILITY_PRIVATE,
+            VISIBILITY_SECRET,
+            NotificationManager.VISIBILITY_NO_OVERRIDE
+    })
+    public @interface NotificationVisibilityOverride{};
+
+    /**
      * Notification category: incoming call (voice or video) or similar synchronous communication request.
      */
     public static final String CATEGORY_CALL = "call";
@@ -2673,7 +2684,17 @@
         if (headsUpContentView != null) headsUpContentView.visitUris(visitor);
 
         if (extras != null) {
-            visitor.accept(extras.getParcelable(EXTRA_AUDIO_CONTENTS_URI));
+            // NOTE: The documentation of EXTRA_AUDIO_CONTENTS_URI explicitly says that it is a
+            // String representation of a Uri, but the previous implementation (and unit test) of
+            // this method has always treated it as a Uri object. Given the inconsistency,
+            // supporting both going forward is the safest choice.
+            Object audioContentsUri = extras.get(EXTRA_AUDIO_CONTENTS_URI);
+            if (audioContentsUri instanceof Uri) {
+                visitor.accept((Uri) audioContentsUri);
+            } else if (audioContentsUri instanceof String) {
+                visitor.accept(Uri.parse((String) audioContentsUri));
+            }
+
             if (extras.containsKey(EXTRA_BACKGROUND_IMAGE_URI)) {
                 visitor.accept(Uri.parse(extras.getString(EXTRA_BACKGROUND_IMAGE_URI)));
             }
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 685c222..6553b61 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -108,13 +108,13 @@
      * Extra value for {@link Settings#EXTRA_CHANNEL_FILTER_LIST}. Include to show fields
      * that have to do with editing do not disturb bypass {(@link #setBypassDnd(boolean)}) .
      */
-    public static final String EDIT_ZEN = "dnd";
+    public static final String EDIT_ZEN = "zen";
     /**
      * Extra value for {@link Settings#EXTRA_CHANNEL_FILTER_LIST}. Include to show fields
      * that have to do with editing conversation settings (demoting or restoring a channel to
      * be a Conversation, changing bubble behavior, or setting the priority of a conversation).
      */
-    public static final String EDIT_CONVERSATION = "convo";
+    public static final String EDIT_CONVERSATION = "conversation";
     /**
      * Extra value for {@link Settings#EXTRA_CHANNEL_FILTER_LIST}. Include to show fields
      * that have to do with editing launcher behavior (showing badges)}.
diff --git a/core/java/android/app/admin/DelegatedAdminReceiver.java b/core/java/android/app/admin/DelegatedAdminReceiver.java
index 25b8eab..36097c9 100644
--- a/core/java/android/app/admin/DelegatedAdminReceiver.java
+++ b/core/java/android/app/admin/DelegatedAdminReceiver.java
@@ -18,6 +18,7 @@
 
 import static android.app.admin.DeviceAdminReceiver.ACTION_CHOOSE_PRIVATE_KEY_ALIAS;
 import static android.app.admin.DeviceAdminReceiver.ACTION_NETWORK_LOGS_AVAILABLE;
+import static android.app.admin.DeviceAdminReceiver.ACTION_SECURITY_LOGS_AVAILABLE;
 import static android.app.admin.DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_ALIAS;
 import static android.app.admin.DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_SENDER_UID;
 import static android.app.admin.DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_URI;
@@ -115,6 +116,29 @@
     }
 
     /**
+     * Called each time a new batch of security logs can be retrieved. This callback method will
+     * only ever be called when security logging is enabled. The logs can only be retrieved while
+     * security logging is enabled.
+     *
+     * <p>If a secondary user or profile is created, this callback won't be received until all users
+     * become affiliated again (even if security logging is enabled). It will also no longer be
+     * possible to retrieve the security logs. See {@link DevicePolicyManager#setAffiliationIds}.
+     *
+     * <p> This callback is only applicable if the delegated app has
+     * {@link DevicePolicyManager#DELEGATION_SECURITY_LOGGING} capability. Additionally, it must
+     * declare an intent filter for {@link DeviceAdminReceiver#ACTION_SECURITY_LOGS_AVAILABLE} in
+     * the receiver's manifest in order to receive this callback. The default implementation
+     * simply throws {@link UnsupportedOperationException}.
+     *
+     * @param context The running context as per {@link #onReceive}.
+     * @param intent The received intent as per {@link #onReceive}.
+     * @see DevicePolicyManager#retrieveSecurityLogs
+     */
+    public void onSecurityLogsAvailable(@NonNull Context context, @NonNull Intent intent) {
+        throw new UnsupportedOperationException("onSecurityLogsAvailable should be implemented");
+    }
+
+    /**
      * Intercept delegated device administrator broadcasts. Implementations should not override
      * this method; implement the convenience callbacks for each action instead.
      */
@@ -132,6 +156,8 @@
             long batchToken = intent.getLongExtra(EXTRA_NETWORK_LOGS_TOKEN, -1);
             int networkLogsCount = intent.getIntExtra(EXTRA_NETWORK_LOGS_COUNT, 0);
             onNetworkLogsAvailable(context, intent, batchToken, networkLogsCount);
+        } else if (ACTION_SECURITY_LOGS_AVAILABLE.equals(action)) {
+            onSecurityLogsAvailable(context, intent);
         } else {
             Log.w(TAG, "Unhandled broadcast: " + action);
         }
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index cccc929..747a2de 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -290,7 +290,6 @@
 
     /**
      * Broadcast action: notify that a new batch of security logs is ready to be collected.
-     * @hide
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     @BroadcastBehavior(explicitOnly = true)
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 56aa9a2..426159f 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1766,6 +1766,16 @@
             "android.app.action.DATA_SHARING_RESTRICTION_APPLIED";
 
     /**
+     * Broadcast action: notify that a value of {@link Settings.Global#DEVICE_POLICY_CONSTANTS}
+     * has been changed.
+     * @hide
+     */
+    @TestApi
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_DEVICE_POLICY_CONSTANTS_CHANGED =
+            "android.app.action.DEVICE_POLICY_CONSTANTS_CHANGED";
+
+    /**
      * Permission policy to prompt user for new permission requests for runtime permissions.
      * Already granted or denied permissions are not affected by this.
      */
@@ -1895,6 +1905,20 @@
     public static final String DELEGATION_CERT_SELECTION = "delegation-cert-selection";
 
     /**
+     * Grants access to {@link #setSecurityLoggingEnabled}, {@link #isSecurityLoggingEnabled},
+     * {@link #retrieveSecurityLogs}, and {@link #retrievePreRebootSecurityLogs}. Once granted the
+     * delegated app will start receiving {@link DelegatedAdminReceiver#onSecurityLogsAvailable}
+     * callback, and Device owner or Profile Owner will no longer receive the
+     * {@link DeviceAdminReceiver#onSecurityLogsAvailable} callback. There can be at most one app
+     * that has this delegation. If another app already had delegated security logging access, it
+     * will lose the delegation when a new app is delegated.
+     *
+     * <p> Can only be granted by Device Owner or Profile Owner of an organnization owned and
+     * managed profile.
+     */
+    public static final String DELEGATION_SECURITY_LOGGING = "delegation-security-logging";
+
+    /**
      * No management for current user in-effect. This is the default.
      * @hide
      */
@@ -2426,7 +2450,7 @@
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag = true, prefix = {"PRIVATE_DNS_MODE_"}, value = {
+    @IntDef(prefix = {"PRIVATE_DNS_MODE_"}, value = {
             PRIVATE_DNS_MODE_UNKNOWN,
             PRIVATE_DNS_MODE_OFF,
             PRIVATE_DNS_MODE_OPPORTUNISTIC,
@@ -6159,13 +6183,22 @@
 
     // STOPSHIP(b/174298501): clarify the expected return value following generateKeyPair call.
     /**
-     * Called by a device or profile owner, or delegated certificate installer, to query whether a
-     * certificate and private key are installed under a given alias.
+     * This API can be called by the following to query whether a certificate and private key are
+     * installed under a given alias:
+     * <ul>
+     *    <li>Device owner</li>
+     *    <li>Profile owner</li>
+     *    <li>Delegated certificate installer</li>
+     *    <li>Credential management app</li>
+     * </ul>
+     *
+     * If called by the credential management app, the alias must exist in the credential
+     * management app's {@link android.security.AppUriAuthenticationPolicy}.
      *
      * @param alias The alias under which the key pair is installed.
      * @return {@code true} if a key pair with this alias exists, {@code false} otherwise.
-     * @throws SecurityException if the caller is not a device or profile owner or a delegated
-     *         certificate installer.
+     * @throws SecurityException if the caller is not a device or profile owner, a delegated
+     *         certificate installer or the credential management app.
      * @see #setDelegatedScopes
      * @see #DELEGATION_CERT_INSTALL
      */
@@ -10004,37 +10037,6 @@
     }
 
     /**
-     * Indicates whether 5g slicing is enabled for specific user.
-     *
-     * This method can be called with permission
-     * {@link android.Manifest.permission#READ_NETWORK_DEVICE_CONFIG} by the profile owner of
-     * a managed profile. And the caller must hold the
-     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission if query for
-     * other users.
-     *
-     * @param userHandle indicates the user to query the state
-     * @return indicates whether 5g Slice is enabled.
-     * @throws SecurityException if the caller is not granted the permission
-     *         {@link android.Manifest.permission#READ_NETWORK_DEVICE_CONFIG}
-     *         and not profile owner of a managed profile, and not granted the permission
-     *         {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} if query for
-     *         other users.
-     * @hide
-     */
-    @SystemApi
-    public boolean isNetworkSlicingEnabledForUser(@NonNull UserHandle userHandle) {
-        throwIfParentInstance("isNetworkSlicingEnabledForUser");
-        if (mService == null) {
-            return false;
-        }
-        try {
-            return mService.isNetworkSlicingEnabled(userHandle.getIdentifier());
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
      * This method is mostly deprecated.
      * Most of the settings that still have an effect have dedicated setter methods or user
      * restrictions. See individual settings for details.
@@ -11253,7 +11255,7 @@
     public void setSecurityLoggingEnabled(@NonNull ComponentName admin, boolean enabled) {
         throwIfParentInstance("setSecurityLoggingEnabled");
         try {
-            mService.setSecurityLoggingEnabled(admin, enabled);
+            mService.setSecurityLoggingEnabled(admin, mContext.getPackageName(), enabled);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
@@ -11272,7 +11274,7 @@
     public boolean isSecurityLoggingEnabled(@Nullable ComponentName admin) {
         throwIfParentInstance("isSecurityLoggingEnabled");
         try {
-            return mService.isSecurityLoggingEnabled(admin);
+            return mService.isSecurityLoggingEnabled(admin, mContext.getPackageName());
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
@@ -11297,10 +11299,12 @@
      * @see #isAffiliatedUser
      * @see DeviceAdminReceiver#onSecurityLogsAvailable
      */
+    @SuppressLint("NullableCollection")
     public @Nullable List<SecurityEvent> retrieveSecurityLogs(@NonNull ComponentName admin) {
         throwIfParentInstance("retrieveSecurityLogs");
         try {
-            ParceledListSlice<SecurityEvent> list = mService.retrieveSecurityLogs(admin);
+            ParceledListSlice<SecurityEvent> list = mService.retrieveSecurityLogs(
+                    admin, mContext.getPackageName());
             if (list != null) {
                 return list.getList();
             } else {
@@ -11450,11 +11454,13 @@
      * @see #isAffiliatedUser
      * @see #retrieveSecurityLogs
      */
+    @SuppressLint("NullableCollection")
     public @Nullable List<SecurityEvent> retrievePreRebootSecurityLogs(
             @NonNull ComponentName admin) {
         throwIfParentInstance("retrievePreRebootSecurityLogs");
         try {
-            ParceledListSlice<SecurityEvent> list = mService.retrievePreRebootSecurityLogs(admin);
+            ParceledListSlice<SecurityEvent> list = mService.retrievePreRebootSecurityLogs(
+                    admin, mContext.getPackageName());
             if (list != null) {
                 return list.getList();
             } else {
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index e98720c..7901791 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -386,10 +386,10 @@
     List<String> getAffiliationIds(in ComponentName admin);
     boolean isAffiliatedUser();
 
-    void setSecurityLoggingEnabled(in ComponentName admin, boolean enabled);
-    boolean isSecurityLoggingEnabled(in ComponentName admin);
-    ParceledListSlice retrieveSecurityLogs(in ComponentName admin);
-    ParceledListSlice retrievePreRebootSecurityLogs(in ComponentName admin);
+    void setSecurityLoggingEnabled(in ComponentName admin, String packageName, boolean enabled);
+    boolean isSecurityLoggingEnabled(in ComponentName admin, String packageName);
+    ParceledListSlice retrieveSecurityLogs(in ComponentName admin, String packageName);
+    ParceledListSlice retrievePreRebootSecurityLogs(in ComponentName admin, String packageName);
     long forceNetworkLogs();
     long forceSecurityLogs();
 
diff --git a/core/java/android/app/people/ConversationStatus.java b/core/java/android/app/people/ConversationStatus.java
index d2a0255..d351683 100644
--- a/core/java/android/app/people/ConversationStatus.java
+++ b/core/java/android/app/people/ConversationStatus.java
@@ -36,7 +36,8 @@
             ACTIVITY_BIRTHDAY,
             ACTIVITY_ANNIVERSARY,
             ACTIVITY_NEW_STORY,
-            ACTIVITY_MEDIA,
+            ACTIVITY_AUDIO,
+            ACTIVITY_VIDEO,
             ACTIVITY_GAME,
             ACTIVITY_LOCATION,
             ACTIVITY_UPCOMING_BIRTHDAY
@@ -44,14 +45,47 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface ActivityType {}
 
+    /**
+     * Constant representing that the conversation user is engaged in an activity that cannot be
+     * more specifically represented by another type.
+     */
     public static final int ACTIVITY_OTHER = 0;
+    /**
+     * Constant representing that today is the conversation user's birthday.
+     */
     public static final int ACTIVITY_BIRTHDAY = 1;
+    /**
+     * Constant representing that the conversation user and the device user are celebrating
+     * and anniversary today.
+     */
     public static final int ACTIVITY_ANNIVERSARY = 2;
+    /**
+     * Constant representing that the conversation user has posted a new story.
+     */
     public static final int ACTIVITY_NEW_STORY = 3;
-    public static final int ACTIVITY_MEDIA = 4;
-    public static final int ACTIVITY_GAME = 5;
-    public static final int ACTIVITY_LOCATION = 6;
-    public static final int ACTIVITY_UPCOMING_BIRTHDAY = 7;
+    /**
+     * Constant representing that the conversation user is listening to music or other audio
+     * like a podcast.
+     */
+    public static final int ACTIVITY_AUDIO = 4;
+    /**
+     * Constant representing that the conversation user is watching video content.
+     */
+    public static final int ACTIVITY_VIDEO = 5;
+    /**
+     * Constant representing that the conversation user is playing a game.
+     */
+    public static final int ACTIVITY_GAME = 6;
+    /**
+     * Constant representing that the conversation user is sharing status with the device user.
+     * Use this to represent a general 'this person is sharing their location with you' status or
+     * a more specific 'this is the current location of this person' status.
+     */
+    public static final int ACTIVITY_LOCATION = 7;
+    /**
+     * Constant representing that the conversation user's birthday is approaching soon.
+     */
+    public static final int ACTIVITY_UPCOMING_BIRTHDAY = 8;
 
     /** @hide */
     @IntDef(prefix = { "AVAILABILITY_" }, value = {
diff --git a/core/java/android/app/time/Capabilities.java b/core/java/android/app/time/Capabilities.java
new file mode 100644
index 0000000..33db721
--- /dev/null
+++ b/core/java/android/app/time/Capabilities.java
@@ -0,0 +1,78 @@
+/*
+ * 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.time;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A capability is the ability for the user to configure something or perform an action. This
+ * information is exposed so that system apps like SettingsUI can be dynamic, rather than
+ * hard-coding knowledge of when configuration or actions are applicable / available to the user.
+ *
+ * <p>Capabilities have states that users cannot change directly. They may influence some
+ * capabilities indirectly by agreeing to certain device-wide behaviors such as location sharing, or
+ * by changing the configuration. See the {@code CAPABILITY_} constants for details.
+ *
+ * <p>Actions have associated methods, see the documentation for each action for details.
+ *
+ * <p>Note: Capabilities are independent of app permissions required to call the associated APIs.
+ *
+ * @hide
+ */
+@SystemApi
+public final class Capabilities {
+
+    /** @hide */
+    @IntDef({ CAPABILITY_NOT_SUPPORTED, CAPABILITY_NOT_ALLOWED, CAPABILITY_NOT_APPLICABLE,
+            CAPABILITY_POSSESSED })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CapabilityState {}
+
+    /**
+     * Indicates that a capability is not supported on this device, e.g. because of form factor or
+     * hardware. The associated UI should usually not be shown to the user.
+     */
+    public static final int CAPABILITY_NOT_SUPPORTED = 10;
+
+    /**
+     * Indicates that a capability is supported on this device, but not allowed for the user, e.g.
+     * if the capability relates to the ability to modify settings the user is not able to.
+     * This could be because of the user's type (e.g. maybe it applies to the primary user only) or
+     * device policy. Depending on the capability, this could mean the associated UI
+     * should be hidden, or displayed but disabled.
+     */
+    public static final int CAPABILITY_NOT_ALLOWED = 20;
+
+    /**
+     * Indicates that a capability is possessed but not currently applicable, e.g. if the
+     * capability relates to the ability to modify settings, the user has the ability to modify
+     * it, but it is currently rendered irrelevant by other settings or other device state (flags,
+     * resource config, etc.). The associated UI may be hidden, disabled, or left visible (but
+     * ineffective) depending on requirements.
+     */
+    public static final int CAPABILITY_NOT_APPLICABLE = 30;
+
+    /** Indicates that a capability is possessed by the user. */
+    public static final int CAPABILITY_POSSESSED = 40;
+
+    private Capabilities() {}
+
+}
diff --git a/telephony/java/android/telephony/data/SliceInfo.aidl b/core/java/android/app/time/TimeCapabilities.aidl
similarity index 82%
copy from telephony/java/android/telephony/data/SliceInfo.aidl
copy to core/java/android/app/time/TimeCapabilities.aidl
index 286ea5e..f44b791 100644
--- a/telephony/java/android/telephony/data/SliceInfo.aidl
+++ b/core/java/android/app/time/TimeCapabilities.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-/** @hide */
-package android.telephony.data;
+package android.app.time;
 
-parcelable SliceInfo;
+parcelable TimeCapabilities;
diff --git a/core/java/android/app/time/TimeCapabilities.java b/core/java/android/app/time/TimeCapabilities.java
new file mode 100644
index 0000000..fff36c4
--- /dev/null
+++ b/core/java/android/app/time/TimeCapabilities.java
@@ -0,0 +1,186 @@
+/*
+ * 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.time;
+
+import android.annotation.NonNull;
+import android.app.time.Capabilities.CapabilityState;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.UserHandle;
+
+import java.util.Objects;
+
+/**
+ * Time-relate capabilities for a user.
+ *
+ * <p>For configuration settings capabilities, the associated settings value can be found via
+ * {@link TimeManager#getTimeCapabilitiesAndConfig()} and may be changed using {@link
+ * TimeManager#updateTimeConfiguration(TimeConfiguration)} (if the user's capabilities
+ * allow).
+ *
+ * @hide
+ */
+public final class TimeCapabilities implements Parcelable {
+
+    public static final @NonNull Creator<TimeCapabilities> CREATOR =
+            new Creator<TimeCapabilities>() {
+                public TimeCapabilities createFromParcel(Parcel in) {
+                    return TimeCapabilities.createFromParcel(in);
+                }
+
+                public TimeCapabilities[] newArray(int size) {
+                    return new TimeCapabilities[size];
+                }
+            };
+
+
+    /**
+     * The user the capabilities are for. This is used for object equality and debugging but there
+     * is no accessor.
+     */
+    @NonNull
+    private final UserHandle mUserHandle;
+    private final @CapabilityState int mConfigureAutoTimeDetectionEnabledCapability;
+    private final @CapabilityState int mSuggestTimeManuallyCapability;
+
+    private TimeCapabilities(@NonNull Builder builder) {
+        this.mUserHandle = Objects.requireNonNull(builder.mUserHandle);
+        this.mConfigureAutoTimeDetectionEnabledCapability =
+                builder.mConfigureAutoDetectionEnabledCapability;
+        this.mSuggestTimeManuallyCapability =
+                builder.mSuggestTimeManuallyCapability;
+    }
+
+    @NonNull
+    private static TimeCapabilities createFromParcel(Parcel in) {
+        UserHandle userHandle = UserHandle.readFromParcel(in);
+        return new TimeCapabilities.Builder(userHandle)
+                .setConfigureAutoTimeDetectionEnabledCapability(in.readInt())
+                .setSuggestTimeManuallyCapability(in.readInt())
+                .build();
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        UserHandle.writeToParcel(mUserHandle, dest);
+        dest.writeInt(mConfigureAutoTimeDetectionEnabledCapability);
+        dest.writeInt(mSuggestTimeManuallyCapability);
+    }
+
+    /**
+     * Returns the capability state associated with the user's ability to modify the automatic time
+     * detection setting.
+     */
+    @CapabilityState
+    public int getConfigureAutoTimeDetectionEnabledCapability() {
+        return mConfigureAutoTimeDetectionEnabledCapability;
+    }
+
+    /**
+     * Returns the capability state associated with the user's ability to manually set time on a
+     * device.
+     */
+    @CapabilityState
+    public int getSuggestTimeManuallyCapability() {
+        return mSuggestTimeManuallyCapability;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        TimeCapabilities that = (TimeCapabilities) o;
+        return mConfigureAutoTimeDetectionEnabledCapability
+                == that.mConfigureAutoTimeDetectionEnabledCapability
+                && mSuggestTimeManuallyCapability == that.mSuggestTimeManuallyCapability
+                && mUserHandle.equals(that.mUserHandle);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mUserHandle, mConfigureAutoTimeDetectionEnabledCapability,
+                mSuggestTimeManuallyCapability);
+    }
+
+    @Override
+    public String toString() {
+        return "TimeCapabilities{"
+                + "mUserHandle=" + mUserHandle
+                + ", mConfigureAutoTimeDetectionEnabledCapability="
+                + mConfigureAutoTimeDetectionEnabledCapability
+                + ", mSuggestTimeManuallyCapability=" + mSuggestTimeManuallyCapability
+                + '}';
+    }
+
+    /**
+     * A builder of {@link TimeCapabilities} objects.
+     *
+     * @hide
+     */
+    public static class Builder {
+        @NonNull private final UserHandle mUserHandle;
+        private @CapabilityState int mConfigureAutoDetectionEnabledCapability;
+        private @CapabilityState int mSuggestTimeManuallyCapability;
+
+        public Builder(@NonNull TimeCapabilities timeCapabilities) {
+            Objects.requireNonNull(timeCapabilities);
+            this.mUserHandle = timeCapabilities.mUserHandle;
+            this.mConfigureAutoDetectionEnabledCapability =
+                    timeCapabilities.mConfigureAutoTimeDetectionEnabledCapability;
+            this.mSuggestTimeManuallyCapability =
+                    timeCapabilities.mSuggestTimeManuallyCapability;
+        }
+
+        public Builder(@NonNull UserHandle userHandle) {
+            this.mUserHandle = Objects.requireNonNull(userHandle);
+        }
+
+        /** Sets the state for automatic time detection config. */
+        public Builder setConfigureAutoTimeDetectionEnabledCapability(
+                @CapabilityState int setConfigureAutoTimeDetectionEnabledCapability) {
+            this.mConfigureAutoDetectionEnabledCapability =
+                    setConfigureAutoTimeDetectionEnabledCapability;
+            return this;
+        }
+
+        /** Sets the state for manual time change. */
+        public Builder setSuggestTimeManuallyCapability(
+                @CapabilityState int suggestTimeManuallyCapability) {
+            this.mSuggestTimeManuallyCapability = suggestTimeManuallyCapability;
+            return this;
+        }
+
+        /** Returns the {@link TimeCapabilities}. */
+        public TimeCapabilities build() {
+            verifyCapabilitySet(mConfigureAutoDetectionEnabledCapability,
+                    "configureAutoDetectionEnabledCapability");
+            verifyCapabilitySet(mSuggestTimeManuallyCapability, "suggestTimeManuallyCapability");
+            return new TimeCapabilities(this);
+        }
+
+        private void verifyCapabilitySet(int value, String name) {
+            if (value == 0) {
+                throw new IllegalStateException(name + " was not set");
+            }
+        }
+    }
+}
diff --git a/telephony/java/android/telephony/data/SliceInfo.aidl b/core/java/android/app/time/TimeCapabilitiesAndConfig.aidl
similarity index 82%
copy from telephony/java/android/telephony/data/SliceInfo.aidl
copy to core/java/android/app/time/TimeCapabilitiesAndConfig.aidl
index 286ea5e..183dcaf 100644
--- a/telephony/java/android/telephony/data/SliceInfo.aidl
+++ b/core/java/android/app/time/TimeCapabilitiesAndConfig.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-/** @hide */
-package android.telephony.data;
+package android.app.time;
 
-parcelable SliceInfo;
+parcelable TimeCapabilitiesAndConfig;
\ No newline at end of file
diff --git a/core/java/android/app/time/TimeCapabilitiesAndConfig.java b/core/java/android/app/time/TimeCapabilitiesAndConfig.java
new file mode 100644
index 0000000..4a10447
--- /dev/null
+++ b/core/java/android/app/time/TimeCapabilitiesAndConfig.java
@@ -0,0 +1,119 @@
+/*
+ * 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.time;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * A pair containing a user's {@link TimeCapabilities} and {@link TimeConfiguration}.
+ *
+ * @hide
+ */
+public final class TimeCapabilitiesAndConfig implements Parcelable {
+
+    public static final @NonNull Creator<TimeCapabilitiesAndConfig> CREATOR =
+            new Creator<TimeCapabilitiesAndConfig>() {
+        @Override
+        public TimeCapabilitiesAndConfig createFromParcel(Parcel source) {
+            return TimeCapabilitiesAndConfig.readFromParcel(source);
+        }
+
+        @Override
+        public TimeCapabilitiesAndConfig[] newArray(int size) {
+            return new TimeCapabilitiesAndConfig[size];
+        }
+    };
+
+    @NonNull
+    private final TimeCapabilities mTimeCapabilities;
+
+    @NonNull
+    private final TimeConfiguration mTimeConfiguration;
+
+    /**
+     * @hide
+     */
+    public TimeCapabilitiesAndConfig(@NonNull TimeCapabilities timeCapabilities,
+            @NonNull TimeConfiguration timeConfiguration) {
+        mTimeCapabilities = Objects.requireNonNull(timeCapabilities);
+        mTimeConfiguration = Objects.requireNonNull(timeConfiguration);
+    }
+
+    @NonNull
+    private static TimeCapabilitiesAndConfig readFromParcel(Parcel in) {
+        TimeCapabilities capabilities = in.readParcelable(null);
+        TimeConfiguration configuration = in.readParcelable(null);
+        return new TimeCapabilitiesAndConfig(capabilities, configuration);
+    }
+
+    /**
+     * Returns the user's time behaviour capabilities.
+     *
+     * @hide
+     */
+    @NonNull
+    public TimeCapabilities getTimeCapabilities() {
+        return mTimeCapabilities;
+    }
+
+    /**
+     * Returns the user's time behaviour configuration.
+     *
+     * @hide
+     */
+    @NonNull
+    public TimeConfiguration getTimeConfiguration() {
+        return mTimeConfiguration;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeParcelable(mTimeCapabilities, flags);
+        dest.writeParcelable(mTimeConfiguration, flags);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        TimeCapabilitiesAndConfig that = (TimeCapabilitiesAndConfig) o;
+        return mTimeCapabilities.equals(that.mTimeCapabilities)
+                && mTimeConfiguration.equals(that.mTimeConfiguration);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mTimeCapabilities, mTimeConfiguration);
+    }
+
+    @Override
+    public String toString() {
+        return "TimeCapabilitiesAndConfig{"
+                + "mTimeCapabilities=" + mTimeCapabilities
+                + ", mTimeConfiguration=" + mTimeConfiguration
+                + '}';
+    }
+}
diff --git a/telephony/java/android/telephony/data/SliceInfo.aidl b/core/java/android/app/time/TimeConfiguration.aidl
similarity index 82%
copy from telephony/java/android/telephony/data/SliceInfo.aidl
copy to core/java/android/app/time/TimeConfiguration.aidl
index 286ea5e..eb5bfd6 100644
--- a/telephony/java/android/telephony/data/SliceInfo.aidl
+++ b/core/java/android/app/time/TimeConfiguration.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-/** @hide */
-package android.telephony.data;
+package android.app.time;
 
-parcelable SliceInfo;
+parcelable TimeConfiguration;
diff --git a/core/java/android/app/time/TimeConfiguration.java b/core/java/android/app/time/TimeConfiguration.java
new file mode 100644
index 0000000..70aede0
--- /dev/null
+++ b/core/java/android/app/time/TimeConfiguration.java
@@ -0,0 +1,141 @@
+/*
+ * 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.time;
+
+import android.annotation.NonNull;
+import android.annotation.StringDef;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * User visible settings that control the behavior of the time zone detector / manual time zone
+ * entry.
+ *
+ * @hide
+ */
+public final class TimeConfiguration implements Parcelable {
+
+    public static final @NonNull Creator<TimeConfiguration> CREATOR =
+            new Creator<TimeConfiguration>() {
+                @Override
+                public TimeConfiguration createFromParcel(Parcel source) {
+                    return TimeConfiguration.readFromParcel(source);
+                }
+
+                @Override
+                public TimeConfiguration[] newArray(int size) {
+                    return new TimeConfiguration[size];
+                }
+            };
+
+    @StringDef(SETTING_AUTO_DETECTION_ENABLED)
+    @Retention(RetentionPolicy.SOURCE)
+    @interface Setting {}
+
+    @Setting
+    private static final String SETTING_AUTO_DETECTION_ENABLED = "autoDetectionEnabled";
+
+    @NonNull
+    private final Bundle mBundle;
+
+    private TimeConfiguration(Builder builder) {
+        this.mBundle = builder.mBundle;
+    }
+
+    /**
+     * Returns the value of the {@link #SETTING_AUTO_DETECTION_ENABLED} setting. This
+     * controls whether a device will attempt to determine the time automatically using
+     * contextual information if the device supports auto detection.
+     */
+    public boolean isAutoDetectionEnabled() {
+        return mBundle.getBoolean(SETTING_AUTO_DETECTION_ENABLED);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeBundle(mBundle);
+    }
+
+    private static TimeConfiguration readFromParcel(Parcel in) {
+        return new TimeConfiguration.Builder()
+                .merge(in.readBundle())
+                .build();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        TimeConfiguration that = (TimeConfiguration) o;
+        return mBundle.kindofEquals(that.mBundle);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mBundle);
+    }
+
+    @Override
+    public String toString() {
+        return "TimeConfiguration{"
+                + "mBundle=" + mBundle
+                + '}';
+    }
+
+    /**
+     * A builder for {@link TimeConfiguration} objects.
+     *
+     * @hide
+     */
+    public static final class Builder {
+        private final Bundle mBundle = new Bundle();
+
+        public Builder() {}
+
+        public Builder(@NonNull TimeConfiguration configuration) {
+            mBundle.putAll(configuration.mBundle);
+        }
+
+        /** Sets whether auto detection is enabled or not. */
+        @NonNull
+        public Builder setAutoDetectionEnabled(boolean enabled) {
+            mBundle.putBoolean(SETTING_AUTO_DETECTION_ENABLED, enabled);
+            return this;
+        }
+
+        Builder merge(@NonNull Bundle bundle) {
+            mBundle.putAll(bundle);
+            return this;
+        }
+
+        /** Returns {@link TimeConfiguration} object. */
+        @NonNull
+        public TimeConfiguration build() {
+            return new TimeConfiguration(this);
+        }
+    }
+}
diff --git a/core/java/android/app/time/TimeManager.java b/core/java/android/app/time/TimeManager.java
index 430960f..c8fa5c8 100644
--- a/core/java/android/app/time/TimeManager.java
+++ b/core/java/android/app/time/TimeManager.java
@@ -75,7 +75,7 @@
     @NonNull
     public TimeZoneCapabilitiesAndConfig getTimeZoneCapabilitiesAndConfig() {
         if (DEBUG) {
-            Log.d(TAG, "getTimeZoneCapabilities called");
+            Log.d(TAG, "getTimeZoneCapabilitiesAndConfig called");
         }
         try {
             return mITimeZoneDetectorService.getCapabilitiesAndConfig();
@@ -85,6 +85,44 @@
     }
 
     /**
+     * Returns the calling user's time capabilities and configuration.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION)
+    @NonNull
+    public TimeCapabilitiesAndConfig getTimeCapabilitiesAndConfig() {
+        if (DEBUG) {
+            Log.d(TAG, "getTimeCapabilitiesAndConfig called");
+        }
+        try {
+            return mITimeDetectorService.getCapabilitiesAndConfig();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Modifies the time detection configuration.
+     *
+     * @return {@code true} if all the configuration settings specified have been set to the
+     * new values, {@code false} if none have
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION)
+    public boolean updateTimeConfiguration(@NonNull TimeConfiguration configuration) {
+        if (DEBUG) {
+            Log.d(TAG, "updateTimeConfiguration called: " + configuration);
+        }
+        try {
+            return mITimeDetectorService.updateConfiguration(configuration);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Modifies the time zone detection configuration.
      *
      * <p>Configuration settings vary in scope: some may be global (affect all users), others may be
@@ -97,11 +135,11 @@
      * capabilities.
      *
      * <p>Attempts to modify configuration settings with capabilities that are {@link
-     * TimeZoneCapabilities#CAPABILITY_NOT_SUPPORTED} or {@link
-     * TimeZoneCapabilities#CAPABILITY_NOT_ALLOWED} will have no effect and a {@code false}
+     * Capabilities#CAPABILITY_NOT_SUPPORTED} or {@link
+     * Capabilities#CAPABILITY_NOT_ALLOWED} will have no effect and a {@code false}
      * will be returned. Modifying configuration settings with capabilities that are {@link
-     * TimeZoneCapabilities#CAPABILITY_NOT_APPLICABLE} or {@link
-     * TimeZoneCapabilities#CAPABILITY_POSSESSED} will succeed. See {@link
+     * Capabilities#CAPABILITY_NOT_APPLICABLE} or {@link
+     * Capabilities#CAPABILITY_POSSESSED} will succeed. See {@link
      * TimeZoneCapabilities} for further details.
      *
      * <p>If the supplied configuration only has some values set, then only the specified settings
diff --git a/core/java/android/app/time/TimeZoneCapabilities.java b/core/java/android/app/time/TimeZoneCapabilities.java
index a27be96..433b420 100644
--- a/core/java/android/app/time/TimeZoneCapabilities.java
+++ b/core/java/android/app/time/TimeZoneCapabilities.java
@@ -16,77 +16,33 @@
 
 package android.app.time;
 
-import android.annotation.IntDef;
+import static android.app.time.Capabilities.CAPABILITY_NOT_APPLICABLE;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.app.time.Capabilities.CapabilityState;
 import android.app.timezonedetector.ManualTimeZoneSuggestion;
 import android.app.timezonedetector.TimeZoneDetector;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.UserHandle;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
 
 /**
- * Time zone-related capabilities for a user. A capability is the ability for the user to configure
- * something or perform an action. This information is exposed so that system apps like SettingsUI
- * can be dynamic, rather than hard-coding knowledge of when configuration or actions are applicable
- * / available to the user.
- *
- * <p>Capabilities have states that users cannot change directly. They may influence some
- * capabilities indirectly by agreeing to certain device-wide behaviors such as location sharing, or
- * by changing the configuration. See the {@code CAPABILITY_} constants for details.
- *
- * <p>Actions have associated methods, see the documentation for each action for details.
+ * Time zone-related capabilities for a user.
  *
  * <p>For configuration settings capabilities, the associated settings value can be found via
  * {@link TimeManager#getTimeZoneCapabilitiesAndConfig()} and may be changed using {@link
  * TimeManager#updateTimeZoneConfiguration(TimeZoneConfiguration)} (if the user's capabilities
  * allow).
  *
- * <p>Note: Capabilities are independent of app permissions required to call the associated APIs.
- *
  * @hide
  */
 @SystemApi
 public final class TimeZoneCapabilities implements Parcelable {
 
-    /** @hide */
-    @IntDef({ CAPABILITY_NOT_SUPPORTED, CAPABILITY_NOT_ALLOWED, CAPABILITY_NOT_APPLICABLE,
-            CAPABILITY_POSSESSED })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface CapabilityState {}
-
-    /**
-     * Indicates that a capability is not supported on this device, e.g. because of form factor or
-     * hardware. The associated UI should usually not be shown to the user.
-     */
-    public static final int CAPABILITY_NOT_SUPPORTED = 10;
-
-    /**
-     * Indicates that a capability is supported on this device, but not allowed for the user, e.g.
-     * if the capability relates to the ability to modify settings the user is not able to.
-     * This could be because of the user's type (e.g. maybe it applies to the primary user only) or
-     * device policy. Depending on the capability, this could mean the associated UI
-     * should be hidden, or displayed but disabled.
-     */
-    public static final int CAPABILITY_NOT_ALLOWED = 20;
-
-    /**
-     * Indicates that a capability is possessed but not currently applicable, e.g. if the
-     * capability relates to the ability to modify settings, the user has the ability to modify
-     * it, but it is currently rendered irrelevant by other settings or other device state (flags,
-     * resource config, etc.). The associated UI may be hidden, disabled, or left visible (but
-     * ineffective) depending on requirements.
-     */
-    public static final int CAPABILITY_NOT_APPLICABLE = 30;
-
-    /** Indicates that a capability is possessed by the user. */
-    public static final int CAPABILITY_POSSESSED = 40;
-
     public static final @NonNull Creator<TimeZoneCapabilities> CREATOR =
             new Creator<TimeZoneCapabilities>() {
                 public TimeZoneCapabilities createFromParcel(Parcel in) {
@@ -159,7 +115,8 @@
      * on a device via {@link TimeZoneDetector#suggestManualTimeZone(ManualTimeZoneSuggestion)}.
      *
      * <p>The suggestion will be ignored in all cases unless the value is {@link
-     * #CAPABILITY_POSSESSED}. See also {@link TimeZoneConfiguration#isAutoDetectionEnabled()}.
+     * Capabilities#CAPABILITY_POSSESSED}. See also
+     * {@link TimeZoneConfiguration#isAutoDetectionEnabled()}.
      *
      * @hide
      */
diff --git a/core/java/android/app/time/TimeZoneCapabilitiesAndConfig.java b/core/java/android/app/time/TimeZoneCapabilitiesAndConfig.java
index f9a0c74..a9ea76f 100644
--- a/core/java/android/app/time/TimeZoneCapabilitiesAndConfig.java
+++ b/core/java/android/app/time/TimeZoneCapabilitiesAndConfig.java
@@ -113,7 +113,7 @@
 
     @Override
     public String toString() {
-        return "TimeZoneDetectorCapabilitiesAndConfig{"
+        return "TimeZoneCapabilitiesAndConfig{"
                 + "mCapabilities=" + mCapabilities
                 + ", mConfiguration=" + mConfiguration
                 + '}';
diff --git a/core/java/android/app/timedetector/ITimeDetectorService.aidl b/core/java/android/app/timedetector/ITimeDetectorService.aidl
index c4546be..9a6c335 100644
--- a/core/java/android/app/timedetector/ITimeDetectorService.aidl
+++ b/core/java/android/app/timedetector/ITimeDetectorService.aidl
@@ -17,6 +17,8 @@
 package android.app.timedetector;
 
 import android.app.time.ExternalTimeSuggestion;
+import android.app.time.TimeCapabilitiesAndConfig;
+import android.app.time.TimeConfiguration;
 import android.app.timedetector.GnssTimeSuggestion;
 import android.app.timedetector.ManualTimeSuggestion;
 import android.app.timedetector.NetworkTimeSuggestion;
@@ -36,6 +38,9 @@
  * {@hide}
  */
 interface ITimeDetectorService {
+  TimeCapabilitiesAndConfig getCapabilitiesAndConfig();
+  boolean updateConfiguration(in TimeConfiguration timeConfiguration);
+
   void suggestExternalTime( in ExternalTimeSuggestion timeSuggestion);
   void suggestGnssTime(in GnssTimeSuggestion timeSuggestion);
   boolean suggestManualTime(in ManualTimeSuggestion timeSuggestion);
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 31781ec..1db7e9d 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -1104,6 +1104,14 @@
                 break;
             case REASON_MAIN_FORCED_BY_USER:
                 sb.append("f");
+                if (subReason > 0) {
+                    // Although not expected and shouldn't happen, this could potentially have a
+                    // sub-reason if the system tries to give a reason when applying the
+                    // FORCED_BY_USER reason. The sub-reason is undefined (though most likely a
+                    // REASON_SUB_FORCED_SYSTEM_FLAG_ sub-reason), but it's better to note it in the
+                    // log than to exclude it altogether.
+                    sb.append("-").append(Integer.toBinaryString(subReason));
+                }
                 break;
             case REASON_MAIN_PREDICTED:
                 sb.append("p");
diff --git a/core/java/android/apphibernation/AppHibernationManager.java b/core/java/android/apphibernation/AppHibernationManager.java
index 7281d50..132cc40 100644
--- a/core/java/android/apphibernation/AppHibernationManager.java
+++ b/core/java/android/apphibernation/AppHibernationManager.java
@@ -17,6 +17,7 @@
 package android.apphibernation;
 
 import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.content.Context;
@@ -54,6 +55,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(value = android.Manifest.permission.MANAGE_APP_HIBERNATION)
     public boolean isHibernatingForUser(@NonNull String packageName) {
         try {
             return mIAppHibernationService.isHibernatingForUser(packageName, mContext.getUserId());
@@ -68,6 +70,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(value = android.Manifest.permission.MANAGE_APP_HIBERNATION)
     public void setHibernatingForUser(@NonNull String packageName, boolean isHibernating) {
         try {
             mIAppHibernationService.setHibernatingForUser(packageName, mContext.getUserId(),
@@ -83,6 +86,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(value = android.Manifest.permission.MANAGE_APP_HIBERNATION)
     public boolean isHibernatingGlobally(@NonNull String packageName) {
         try {
             return mIAppHibernationService.isHibernatingGlobally(packageName);
@@ -99,6 +103,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(value = android.Manifest.permission.MANAGE_APP_HIBERNATION)
     public void setHibernatingGlobally(@NonNull String packageName, boolean isHibernating) {
         try {
             mIAppHibernationService.setHibernatingGlobally(packageName, isHibernating);
diff --git a/core/java/android/bluetooth/le/ScanRecord.java b/core/java/android/bluetooth/le/ScanRecord.java
index c0c1aa1..794b512 100644
--- a/core/java/android/bluetooth/le/ScanRecord.java
+++ b/core/java/android/bluetooth/le/ScanRecord.java
@@ -29,6 +29,7 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Predicate;
 
 /**
  * Represents a scan record from Bluetooth LE scan.
@@ -168,6 +169,27 @@
         return mBytes;
     }
 
+    /**
+     * Test if any fields contained inside this scan record are matched by the
+     * given matcher.
+     *
+     * @hide
+     */
+    public boolean matchesAnyField(@NonNull Predicate<byte[]> matcher) {
+        int pos = 0;
+        while (pos < mBytes.length) {
+            final int length = mBytes[pos] & 0xFF;
+            if (length == 0) {
+                break;
+            }
+            if (matcher.test(Arrays.copyOfRange(mBytes, pos, pos + length + 1))) {
+                return true;
+            }
+            pos += length + 1;
+        }
+        return false;
+    }
+
     private ScanRecord(List<ParcelUuid> serviceUuids,
             List<ParcelUuid> serviceSolicitationUuids,
             SparseArray<byte[]> manufacturerData,
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 190ef1a..64ca92f 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4219,7 +4219,8 @@
      * @see #getSystemService(String)
      * @hide
      */
-    @TestApi public static final String TEST_NETWORK_SERVICE = "test_network";
+    @TestApi @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public static final String TEST_NETWORK_SERVICE = "test_network";
 
     /**
      * Use with {@link #getSystemService(String)} to retrieve a {@link
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index adf9ff3..96b8fbe 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -28,6 +28,7 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.app.AppGlobals;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ActivityInfo;
@@ -3771,6 +3772,7 @@
      * has just been stopped (which is no longer running).
      * @hide
      */
+    @TestApi
     public static final String ACTION_USER_STOPPED =
             "android.intent.action.USER_STOPPED";
 
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
index 29edd40..ba6416d 100644
--- a/core/java/android/content/pm/parsing/ParsingPackage.java
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -34,6 +34,7 @@
 import android.content.pm.parsing.component.ParsedProcess;
 import android.content.pm.parsing.component.ParsedProvider;
 import android.content.pm.parsing.component.ParsedService;
+import android.content.pm.parsing.component.ParsedUsesPermission;
 import android.os.Bundle;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
@@ -89,7 +90,7 @@
 
     ParsingPackage addReqFeature(FeatureInfo reqFeature);
 
-    ParsingPackage addRequestedPermission(String permission);
+    ParsingPackage addUsesPermission(ParsedUsesPermission parsedUsesPermission);
 
     ParsingPackage addService(ParsedService parsedService);
 
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
index 067787d..b3c26ab 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -44,6 +44,7 @@
 import android.content.pm.parsing.component.ParsedProcess;
 import android.content.pm.parsing.component.ParsedProvider;
 import android.content.pm.parsing.component.ParsedService;
+import android.content.pm.parsing.component.ParsedUsesPermission;
 import android.content.res.TypedArray;
 import android.os.Build;
 import android.os.Bundle;
@@ -71,6 +72,7 @@
 import com.android.internal.util.Parcelling.BuiltIn.ForStringSet;
 
 import java.security.PublicKey;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
@@ -227,8 +229,8 @@
     protected List<String> adoptPermissions = emptyList();
 
     @NonNull
-    @DataClass.ParcelWith(ForInternedStringList.class)
-    private List<String> requestedPermissions = emptyList();
+    private List<ParsedUsesPermission> usesPermissions = emptyList();
+
     @NonNull
     @DataClass.ParcelWith(ForInternedStringList.class)
     private List<String> implicitPermissions = emptyList();
@@ -691,9 +693,8 @@
     }
 
     @Override
-    public ParsingPackageImpl addRequestedPermission(String permission) {
-        this.requestedPermissions = CollectionUtils.add(this.requestedPermissions,
-                TextUtils.safeIntern(permission));
+    public ParsingPackageImpl addUsesPermission(ParsedUsesPermission permission) {
+        this.usesPermissions = CollectionUtils.add(this.usesPermissions, permission);
         return this;
     }
 
@@ -1134,7 +1135,7 @@
         dest.writeByteArray(this.restrictUpdateHash);
         dest.writeStringList(this.originalPackages);
         sForInternedStringList.parcel(this.adoptPermissions, dest, flags);
-        sForInternedStringList.parcel(this.requestedPermissions, dest, flags);
+        dest.writeTypedList(this.usesPermissions);
         sForInternedStringList.parcel(this.implicitPermissions, dest, flags);
         sForStringSet.parcel(this.upgradeKeySets, dest, flags);
         dest.writeMap(this.keySetMapping);
@@ -1255,7 +1256,7 @@
         this.restrictUpdateHash = in.createByteArray();
         this.originalPackages = in.createStringArrayList();
         this.adoptPermissions = sForInternedStringList.unparcel(in);
-        this.requestedPermissions = sForInternedStringList.unparcel(in);
+        this.usesPermissions = in.createTypedArrayList(ParsedUsesPermission.CREATOR);
         this.implicitPermissions = sForInternedStringList.unparcel(in);
         this.upgradeKeySets = sForStringSet.unparcel(in);
         this.keySetMapping = in.readHashMap(boot);
@@ -1551,11 +1552,23 @@
     @NonNull
     @Override
     public List<String> getRequestedPermissions() {
+        final List<ParsedUsesPermission> usesPermissions = getUsesPermissions();
+        final int size = usesPermissions.size();
+        final List<String> requestedPermissions = new ArrayList<>(size);
+        for (int i = 0; i < size; i++) {
+            requestedPermissions.add(usesPermissions.get(i).name);
+        }
         return requestedPermissions;
     }
 
     @NonNull
     @Override
+    public List<ParsedUsesPermission> getUsesPermissions() {
+        return usesPermissions;
+    }
+
+    @NonNull
+    @Override
     public List<String> getImplicitPermissions() {
         return implicitPermissions;
     }
diff --git a/core/java/android/content/pm/parsing/ParsingPackageRead.java b/core/java/android/content/pm/parsing/ParsingPackageRead.java
index f7f3e19..9f52183 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageRead.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageRead.java
@@ -37,6 +37,7 @@
 import android.content.pm.parsing.component.ParsedProcess;
 import android.content.pm.parsing.component.ParsedProvider;
 import android.content.pm.parsing.component.ParsedService;
+import android.content.pm.parsing.component.ParsedUsesPermission;
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.util.ArraySet;
@@ -45,6 +46,7 @@
 import android.util.SparseIntArray;
 
 import java.security.PublicKey;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -193,6 +195,14 @@
     List<FeatureInfo> getReqFeatures();
 
     /**
+     * @deprecated consider migrating to {@link #getUsesPermissions} which has
+     *             more parsed details, such as flags
+     */
+    @NonNull
+    @Deprecated
+    List<String> getRequestedPermissions();
+
+    /**
      * All the permissions declared. This is an effective set, and may include permissions
      * transformed from split/migrated permissions from previous versions, so may not be exactly
      * what the package declares in its manifest.
@@ -200,7 +210,7 @@
      * @see R.styleable#AndroidManifestUsesPermission
      */
     @NonNull
-    List<String> getRequestedPermissions();
+    List<ParsedUsesPermission> getUsesPermissions();
 
     /**
      * Returns the properties set on the application
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index 0c033fd..2be0157 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -67,6 +67,7 @@
 import android.content.pm.parsing.component.ParsedProviderUtils;
 import android.content.pm.parsing.component.ParsedService;
 import android.content.pm.parsing.component.ParsedServiceUtils;
+import android.content.pm.parsing.component.ParsedUsesPermission;
 import android.content.pm.parsing.result.ParseInput;
 import android.content.pm.parsing.result.ParseInput.DeferredError;
 import android.content.pm.parsing.result.ParseResult;
@@ -119,6 +120,7 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.StringTokenizer;
 
@@ -1206,6 +1208,10 @@
                 requiredNotFeatures.add(feature);
             }
 
+            final int usesPermissionFlags = sa.getInt(
+                com.android.internal.R.styleable.AndroidManifestUsesPermission_usesPermissionFlags,
+                0);
+
             final int outerDepth = parser.getDepth();
             int type;
             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -1270,14 +1276,31 @@
                 }
             }
 
-            if (!pkg.getRequestedPermissions().contains(name)) {
-                pkg.addRequestedPermission(name.intern());
-            } else {
-                Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: "
-                        + name + " in package: " + pkg.getPackageName() + " at: "
-                        + parser.getPositionDescription());
+            // Quietly ignore duplicate permission requests, but fail loudly if
+            // the two requests have conflicting flags
+            boolean found = false;
+            final List<ParsedUsesPermission> usesPermissions = pkg.getUsesPermissions();
+            final int size = usesPermissions.size();
+            for (int i = 0; i < size; i++) {
+                final ParsedUsesPermission usesPermission = usesPermissions.get(i);
+                if (Objects.equals(usesPermission.name, name)) {
+                    if (usesPermission.usesPermissionFlags != usesPermissionFlags) {
+                        return input.error("Conflicting uses-permissions flags: "
+                                + name + " in package: " + pkg.getPackageName() + " at: "
+                                + parser.getPositionDescription());
+                    } else {
+                        Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: "
+                                + name + " in package: " + pkg.getPackageName() + " at: "
+                                + parser.getPositionDescription());
+                    }
+                    found = true;
+                    break;
+                }
             }
 
+            if (!found) {
+                pkg.addUsesPermission(new ParsedUsesPermission(name, usesPermissionFlags));
+            }
             return success;
         } finally {
             sa.recycle();
@@ -2755,7 +2778,7 @@
                     newPermsMsg.append(' ');
                 }
                 newPermsMsg.append(npi.name);
-                pkg.addRequestedPermission(npi.name)
+                pkg.addUsesPermission(new ParsedUsesPermission(npi.name, 0))
                         .addImplicitPermission(npi.name);
             }
         }
@@ -2777,7 +2800,7 @@
             for (int in = 0; in < newPerms.size(); in++) {
                 final String perm = newPerms.get(in);
                 if (!requestedPermissions.contains(perm)) {
-                    pkg.addRequestedPermission(perm)
+                    pkg.addUsesPermission(new ParsedUsesPermission(perm, 0))
                             .addImplicitPermission(perm);
                 }
             }
diff --git a/core/java/android/content/pm/parsing/component/ParsedUsesPermission.java b/core/java/android/content/pm/parsing/component/ParsedUsesPermission.java
new file mode 100644
index 0000000..b9c2e36
--- /dev/null
+++ b/core/java/android/content/pm/parsing/component/ParsedUsesPermission.java
@@ -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 android.content.pm.parsing.component;
+
+import static android.content.pm.parsing.ParsingPackageImpl.sForInternedString;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A {@link android.R.styleable#AndroidManifestUsesPermission
+ * &lt;uses-permission&gt;} tag parsed from the manifest.
+ *
+ * @hide
+ */
+public class ParsedUsesPermission implements Parcelable {
+    /** Name of the permission requested */
+    public @NonNull String name;
+
+    /** Set of flags that should apply to this permission request. */
+    public @UsesPermissionFlags int usesPermissionFlags;
+
+    /**
+     * Strong assertion by a developer that they will never use this permission
+     * to derive the physical location of the device, regardless of
+     * ACCESS_FINE_LOCATION and/or ACCESS_COARSE_LOCATION being granted.
+     */
+    public static final int FLAG_NEVER_FOR_LOCATION = 0x1;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, prefix = { "FLAG_" }, value = {
+            FLAG_NEVER_FOR_LOCATION
+    })
+    public @interface UsesPermissionFlags {}
+
+    public ParsedUsesPermission(@NonNull String name,
+            @UsesPermissionFlags int usesPermissionFlags) {
+        this.name = name.intern();
+        this.usesPermissionFlags = usesPermissionFlags;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        sForInternedString.parcel(this.name, dest, flags);
+        dest.writeInt(usesPermissionFlags);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    protected ParsedUsesPermission(@NonNull Parcel in) {
+        this.name = sForInternedString.unparcel(in);
+        this.usesPermissionFlags = in.readInt();
+    }
+
+    public static final @NonNull Parcelable.Creator<ParsedUsesPermission> CREATOR
+            = new Parcelable.Creator<ParsedUsesPermission>() {
+        @Override
+        public ParsedUsesPermission[] newArray(int size) {
+            return new ParsedUsesPermission[size];
+        }
+
+        @Override
+        public ParsedUsesPermission createFromParcel(@NonNull Parcel in) {
+            return new ParsedUsesPermission(in);
+        }
+    };
+}
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index d7225cc..439c639 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -20,6 +20,7 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ApplicationInfo;
 import android.graphics.Canvas;
+import android.graphics.Insets;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.Region;
@@ -28,6 +29,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.DisplayMetrics;
+import android.view.InsetsSourceControl;
 import android.view.InsetsState;
 import android.view.MotionEvent;
 import android.view.WindowManager;
@@ -423,13 +425,38 @@
         }
 
         /**
-         * Translate an InsetsState in screen coordinates into the app window's coordinates.
+         * Translate an {@link InsetsState} in screen coordinates into the app window's coordinates.
          */
         public void translateInsetsStateInScreenToAppWindow(InsetsState state) {
             state.scale(applicationInvertedScale);
         }
 
         /**
+         * Translate {@link InsetsSourceControl}s in screen coordinates into the app window's
+         * coordinates.
+         */
+        public void translateSourceControlsInScreenToAppWindow(InsetsSourceControl[] controls) {
+            if (controls == null) {
+                return;
+            }
+            final float scale = applicationInvertedScale;
+            if (scale == 1f) {
+                return;
+            }
+            for (InsetsSourceControl control : controls) {
+                if (control == null) {
+                    continue;
+                }
+                final Insets hint = control.getInsetsHint();
+                control.setInsetsHint(
+                        (int) (scale * hint.left),
+                        (int) (scale * hint.top),
+                        (int) (scale * hint.right),
+                        (int) (scale * hint.bottom));
+            }
+        }
+
+        /**
          * Translate a Point in screen coordinates into the app window's coordinates.
          */
         public void translatePointInScreenToAppWindow(PointF point) {
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index 1fdce5e..304b2af 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -29,6 +29,7 @@
 import android.annotation.SystemService;
 import android.annotation.TestApi;
 import android.content.Context;
+import android.os.IBinder;
 import android.os.RemoteException;
 import android.security.keystore.KeyProperties;
 import android.util.Slog;
@@ -47,13 +48,6 @@
     private static final String TAG = "BiometricManager";
 
     /**
-     * An ID that should match any biometric sensor on the device.
-     *
-     * @hide
-     */
-    public static final int SENSOR_ID_ANY = -1;
-
-    /**
      * No error detected.
      */
     public static final int BIOMETRIC_SUCCESS =
@@ -410,6 +404,36 @@
     }
 
     /**
+     * Requests all other biometric sensors to resetLockout. Note that this is a "time bound"
+     * See the {@link android.hardware.biometrics.fingerprint.ISession#resetLockout(int,
+     * HardwareAuthToken)} and {@link android.hardware.biometrics.face.ISession#resetLockout(int,
+     * HardwareAuthToken)} documentation for complete details.
+     *
+     * @param token A binder from the caller, for the service to linkToDeath
+     * @param opPackageName Caller's package name
+     * @param fromSensorId The originating sensor that just authenticated. Note that this MUST
+     *                     be a sensor that meets {@link Authenticators#BIOMETRIC_STRONG} strength.
+     *                     The strength will also be enforced on the BiometricService side.
+     * @param userId The user that authentication succeeded for, and also the user that resetLockout
+     *               should be applied to.
+     * @param hardwareAuthToken A valid HAT generated upon successful biometric authentication. Note
+     *                          that it is not necessary for the HAT to contain a challenge.
+     * @hide
+     */
+    @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+    public void resetLockoutTimeBound(IBinder token, String opPackageName, int fromSensorId,
+            int userId, byte[] hardwareAuthToken) {
+        if (mService != null) {
+            try {
+                mService.resetLockoutTimeBound(token, opPackageName, fromSensorId, userId,
+                        hardwareAuthToken);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
      * Provides a localized string that may be used as the label for a button that invokes
      * {@link BiometricPrompt}.
      *
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index 4f6a7c7..2e51dc4 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -16,6 +16,7 @@
 
 package android.hardware.biometrics;
 
+import static android.Manifest.permission.TEST_BIOMETRIC;
 import static android.Manifest.permission.USE_BIOMETRIC;
 import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
 import static android.hardware.biometrics.BiometricManager.Authenticators;
@@ -25,6 +26,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.TestApi;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.hardware.face.FaceManager;
@@ -45,6 +47,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.security.Signature;
+import java.util.List;
 import java.util.concurrent.Executor;
 
 import javax.crypto.Cipher;
@@ -339,6 +342,46 @@
         }
 
         /**
+         * If non-empty, requests authentication to be performed only if the sensor is contained
+         * within the list. Note that the actual sensor presented to the user/test will meet all
+         * constraints specified within this builder. For example, on a device with the below
+         * configuration:
+         *
+         * SensorId: 1, Strength: BIOMETRIC_STRONG
+         * SensorId: 2, Strength: BIOMETRIC_WEAK
+         *
+         * If authentication is invoked with setAllowedAuthenticators(BIOMETRIC_STRONG) and
+         * setAllowedSensorIds(2), then no sensor will be eligible for authentication.
+         *
+         * @see {@link BiometricManager#getSensorProperties()}
+         *
+         * @param sensorIds Sensor IDs to constrain this authentication to.
+         * @return This builder
+         * @hide
+         */
+        @TestApi
+        @NonNull
+        @RequiresPermission(anyOf = {TEST_BIOMETRIC, USE_BIOMETRIC_INTERNAL})
+        public Builder setAllowedSensorIds(@NonNull List<Integer> sensorIds) {
+            mPromptInfo.setAllowedSensorIds(sensorIds);
+            return this;
+        }
+
+        /**
+         * @param allow If true, allows authentication when the calling package is not in the
+         *              foreground. This is set to false by default.
+         * @return This builder
+         * @hide
+         */
+        @TestApi
+        @NonNull
+        @RequiresPermission(anyOf = {TEST_BIOMETRIC, USE_BIOMETRIC_INTERNAL})
+        public Builder setAllowBackgroundAuthentication(boolean allow) {
+            mPromptInfo.setAllowBackgroundAuthentication(allow);
+            return this;
+        }
+
+        /**
          * If set check the Device Policy Manager for disabled biometrics.
          *
          * @param checkDevicePolicyManager
@@ -364,21 +407,6 @@
         }
 
         /**
-         * If set, authenticate using the biometric sensor with the given ID.
-         *
-         * @param sensorId The ID of a biometric sensor, or -1 to allow any sensor (default).
-         * @return This builder.
-         *
-         * @hide
-         */
-        @RequiresPermission(USE_BIOMETRIC_INTERNAL)
-        @NonNull
-        public Builder setSensorId(int sensorId) {
-            mPromptInfo.setSensorId(sensorId);
-            return this;
-        }
-
-        /**
          * Creates a {@link BiometricPrompt}.
          *
          * @return An instance of {@link BiometricPrompt}.
@@ -596,6 +624,25 @@
     }
 
     /**
+     * @return The values set by {@link Builder#setAllowedSensorIds(List)}
+     * @hide
+     */
+    @TestApi
+    @NonNull
+    public List<Integer> getAllowedSensorIds() {
+        return mPromptInfo.getAllowedSensorIds();
+    }
+
+    /**
+     * @return The value set by {@link Builder#setAllowBackgroundAuthentication(boolean)}
+     * @hide
+     */
+    @TestApi
+    public boolean isAllowBackgroundAuthentication() {
+        return mPromptInfo.isAllowBackgroundAuthentication();
+    }
+
+    /**
      * A wrapper class for the cryptographic operations supported by BiometricPrompt.
      *
      * <p>Currently the framework supports {@link Signature}, {@link Cipher}, {@link Mac}, and
diff --git a/telephony/java/android/telephony/data/SliceInfo.aidl b/core/java/android/hardware/biometrics/ComponentInfoInternal.aidl
similarity index 81%
copy from telephony/java/android/telephony/data/SliceInfo.aidl
copy to core/java/android/hardware/biometrics/ComponentInfoInternal.aidl
index 286ea5e..0c780cc 100644
--- a/telephony/java/android/telephony/data/SliceInfo.aidl
+++ b/core/java/android/hardware/biometrics/ComponentInfoInternal.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * 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.
@@ -13,8 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.hardware.biometrics;
 
-/** @hide */
-package android.telephony.data;
-
-parcelable SliceInfo;
+parcelable ComponentInfoInternal;
\ No newline at end of file
diff --git a/core/java/android/hardware/biometrics/ComponentInfoInternal.java b/core/java/android/hardware/biometrics/ComponentInfoInternal.java
new file mode 100644
index 0000000..3b61a56
--- /dev/null
+++ b/core/java/android/hardware/biometrics/ComponentInfoInternal.java
@@ -0,0 +1,101 @@
+/*
+ * 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.hardware.biometrics;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * The internal class for storing the component info for a subsystem of the biometric sensor,
+ * as defined in {@link android.hardware.biometrics.common.ComponentInfo}.
+ * @hide
+ */
+public class ComponentInfoInternal implements Parcelable {
+
+    @NonNull public final String componentId;
+    @NonNull public final String hardwareVersion;
+    @NonNull public final String firmwareVersion;
+    @NonNull public final String serialNumber;
+    @NonNull public final String softwareVersion;
+
+    /**
+     * Constructs a {@link ComponentInfoInternal} from another instance.
+     * @hide
+     */
+    public static ComponentInfoInternal from(@NonNull ComponentInfoInternal comp) {
+        return new ComponentInfoInternal(comp.componentId, comp.hardwareVersion,
+                comp.firmwareVersion, comp.serialNumber, comp.softwareVersion);
+    }
+
+    /**
+     * @hide
+     */
+    public ComponentInfoInternal(@NonNull String componentId, @NonNull String hardwareVersion,
+            @NonNull String firmwareVersion, @NonNull String serialNumber,
+            @NonNull String softwareVersion) {
+        this.componentId = componentId;
+        this.hardwareVersion = hardwareVersion;
+        this.firmwareVersion = firmwareVersion;
+        this.serialNumber = serialNumber;
+        this.softwareVersion = softwareVersion;
+    }
+
+    protected ComponentInfoInternal(Parcel in) {
+        componentId = in.readString();
+        hardwareVersion = in.readString();
+        firmwareVersion = in.readString();
+        serialNumber = in.readString();
+        softwareVersion = in.readString();
+    }
+
+    public static final Creator<ComponentInfoInternal> CREATOR =
+            new Creator<ComponentInfoInternal>() {
+        @Override
+        public ComponentInfoInternal createFromParcel(Parcel in) {
+            return new ComponentInfoInternal(in);
+        }
+
+        @Override
+        public ComponentInfoInternal[] newArray(int size) {
+            return new ComponentInfoInternal[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(componentId);
+        dest.writeString(hardwareVersion);
+        dest.writeString(firmwareVersion);
+        dest.writeString(serialNumber);
+        dest.writeString(softwareVersion);
+    }
+
+    @Override
+    public String toString() {
+        return "ComponentId: " + componentId
+                + ", HardwareVersion: " + hardwareVersion
+                + ", FirmwareVersion: " + firmwareVersion
+                + ", SerialNumber " + serialNumber
+                + ", SoftwareVersion: " + softwareVersion;
+    }
+}
diff --git a/core/java/android/hardware/biometrics/IAuthService.aidl b/core/java/android/hardware/biometrics/IAuthService.aidl
index 1472bb9..86df099 100644
--- a/core/java/android/hardware/biometrics/IAuthService.aidl
+++ b/core/java/android/hardware/biometrics/IAuthService.aidl
@@ -69,6 +69,10 @@
     // land as SIDs, and are used during key generation.
     long[] getAuthenticatorIds();
 
+    // See documentation in BiometricManager.
+    void resetLockoutTimeBound(IBinder token, String opPackageName, int fromSensorId, int userId,
+            in byte[] hardwareAuthToken);
+
     // Provides a localized string that may be used as the label for a button that invokes
     // BiometricPrompt.
     CharSequence getButtonLabel(int userId, String opPackageName, int authenticators);
diff --git a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl
index 7639c5d..876513f 100644
--- a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl
@@ -48,7 +48,7 @@
     // startPreparedClient().
     void prepareForAuthentication(boolean requireConfirmation, IBinder token, long operationId,
             int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
-            int cookie);
+            int cookie, boolean allowBackgroundAuthentication);
 
     // Starts authentication with the previously prepared client.
     void startPreparedClient(int cookie);
@@ -70,4 +70,8 @@
 
     // Gets the authenticator ID representing the current set of enrolled templates
     long getAuthenticatorId(int callingUserId);
+
+    // Requests the sensor to reset its lockout state
+    void resetLockout(IBinder token, String opPackageName, int userId,
+            in byte[] hardwareAuthToken);
 }
diff --git a/core/java/android/hardware/biometrics/IBiometricService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl
index 6d8bf0f..64b5118 100644
--- a/core/java/android/hardware/biometrics/IBiometricService.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricService.aidl
@@ -74,6 +74,10 @@
     // land as SIDs, and are used during key generation.
     long[] getAuthenticatorIds(int callingUserId);
 
+    // See documentation in BiometricManager.
+    void resetLockoutTimeBound(IBinder token, String opPackageName, int fromSensorId, int userId,
+            in byte[] hardwareAuthToken);
+
     int getCurrentStrength(int sensorId);
 
     // Returns a bit field of the modality (or modalities) that are will be used for authentication.
diff --git a/core/java/android/hardware/biometrics/PromptInfo.java b/core/java/android/hardware/biometrics/PromptInfo.java
index 0e99f31..339c654 100644
--- a/core/java/android/hardware/biometrics/PromptInfo.java
+++ b/core/java/android/hardware/biometrics/PromptInfo.java
@@ -21,6 +21,9 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Contains the information set/requested by the caller of the {@link BiometricPrompt}
  * @hide
@@ -40,7 +43,8 @@
     private @BiometricManager.Authenticators.Types int mAuthenticators;
     private boolean mDisallowBiometricsIfPolicyExists;
     private boolean mReceiveSystemEvents;
-    private int mSensorId = -1;
+    @NonNull private List<Integer> mAllowedSensorIds = new ArrayList<>();
+    private boolean mAllowBackgroundAuthentication;
 
     public PromptInfo() {
 
@@ -60,7 +64,8 @@
         mAuthenticators = in.readInt();
         mDisallowBiometricsIfPolicyExists = in.readBoolean();
         mReceiveSystemEvents = in.readBoolean();
-        mSensorId = in.readInt();
+        mAllowedSensorIds = in.readArrayList(Integer.class.getClassLoader());
+        mAllowBackgroundAuthentication = in.readBoolean();
     }
 
     public static final Creator<PromptInfo> CREATOR = new Creator<PromptInfo>() {
@@ -95,7 +100,17 @@
         dest.writeInt(mAuthenticators);
         dest.writeBoolean(mDisallowBiometricsIfPolicyExists);
         dest.writeBoolean(mReceiveSystemEvents);
-        dest.writeInt(mSensorId);
+        dest.writeList(mAllowedSensorIds);
+        dest.writeBoolean(mAllowBackgroundAuthentication);
+    }
+
+    public boolean containsTestConfigurations() {
+        if (!mAllowedSensorIds.isEmpty()) {
+            return true;
+        } else if (mAllowBackgroundAuthentication) {
+            return true;
+        }
+        return false;
     }
 
     public boolean containsPrivateApiConfigurations() {
@@ -169,8 +184,12 @@
         mReceiveSystemEvents = receiveSystemEvents;
     }
 
-    public void setSensorId(int sensorId) {
-        mSensorId = sensorId;
+    public void setAllowedSensorIds(@NonNull List<Integer> sensorIds) {
+        mAllowedSensorIds = sensorIds;
+    }
+
+    public void setAllowBackgroundAuthentication(boolean allow) {
+        mAllowBackgroundAuthentication = allow;
     }
 
     // Getters
@@ -234,7 +253,12 @@
         return mReceiveSystemEvents;
     }
 
-    public int getSensorId() {
-        return mSensorId;
+    @NonNull
+    public List<Integer> getAllowedSensorIds() {
+        return mAllowedSensorIds;
+    }
+
+    public boolean isAllowBackgroundAuthentication() {
+        return mAllowBackgroundAuthentication;
     }
 }
diff --git a/core/java/android/hardware/biometrics/SensorProperties.java b/core/java/android/hardware/biometrics/SensorProperties.java
index 360f138..3b9cad4 100644
--- a/core/java/android/hardware/biometrics/SensorProperties.java
+++ b/core/java/android/hardware/biometrics/SensorProperties.java
@@ -17,10 +17,13 @@
 package android.hardware.biometrics;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.TestApi;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * The base class containing all modality-agnostic information.
@@ -56,15 +59,93 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface Strength {}
 
+    /**
+     * A class storing the component info for a subsystem of the sensor.
+     */
+    public static final class ComponentInfo {
+        @NonNull private final String mComponentId;
+        @NonNull private final String mHardwareVersion;
+        @NonNull private final String mFirmwareVersion;
+        @NonNull private final String mSerialNumber;
+        @NonNull private final String mSoftwareVersion;
+
+        /**
+         * @hide
+         */
+        public ComponentInfo(@NonNull String componentId, @NonNull String hardwareVersion,
+                @NonNull String firmwareVersion, @NonNull String serialNumber,
+                @NonNull String softwareVersion) {
+            mComponentId = componentId;
+            mHardwareVersion = hardwareVersion;
+            mFirmwareVersion = firmwareVersion;
+            mSerialNumber = serialNumber;
+            mSoftwareVersion = softwareVersion;
+        }
+
+        /**
+         * @return The unique identifier for the subsystem.
+         */
+        @NonNull
+        public String getComponentId() {
+            return mComponentId;
+        }
+
+        /**
+         * @return The hardware version for the subsystem. For example, <vendor>/<model>/<revision>.
+         */
+        @NonNull
+        public String getHardwareVersion() {
+            return mHardwareVersion;
+        }
+
+        /**
+         * @return The firmware version for the subsystem.
+         */
+        @NonNull
+        public String getFirmwareVersion() {
+            return mFirmwareVersion;
+        }
+
+        /**
+         * @return The serial number for the subsystem.
+         */
+        @NonNull
+        public String getSerialNumber() {
+            return mSerialNumber;
+        }
+
+        /**
+         * @return The software version for the subsystem.
+         * For example, <vendor>/<version>/<revision>.
+         */
+        @NonNull
+        public String getSoftwareVersion() {
+            return mSoftwareVersion;
+        }
+
+        /**
+         * Constructs a {@link ComponentInfo} from the internal parcelable representation.
+         * @hide
+         */
+        public static ComponentInfo from(ComponentInfoInternal internalComp) {
+            return new ComponentInfo(internalComp.componentId, internalComp.hardwareVersion,
+                    internalComp.firmwareVersion, internalComp.serialNumber,
+                    internalComp.softwareVersion);
+        }
+    }
+
     private final int mSensorId;
     @Strength private final int mSensorStrength;
+    private final List<ComponentInfo> mComponentInfo;
 
     /**
      * @hide
      */
-    public SensorProperties(int sensorId, @Strength int sensorStrength) {
+    public SensorProperties(int sensorId, @Strength int sensorStrength,
+            List<ComponentInfo> componentInfo) {
         mSensorId = sensorId;
         mSensorStrength = sensorStrength;
+        mComponentInfo = componentInfo;
     }
 
     /**
@@ -83,10 +164,23 @@
     }
 
     /**
+     * @return The sensor's component info.
+     */
+    @NonNull
+    public List<ComponentInfo> getComponentInfo() {
+        return mComponentInfo;
+    }
+
+    /**
      * Constructs a {@link SensorProperties} from the internal parcelable representation.
      * @hide
      */
     public static SensorProperties from(SensorPropertiesInternal internalProp) {
-        return new SensorProperties(internalProp.sensorId, internalProp.sensorStrength);
+        final List<ComponentInfo> componentInfo = new ArrayList<>();
+        for (ComponentInfoInternal internalComp : internalProp.componentInfo) {
+            componentInfo.add(ComponentInfo.from(internalComp));
+        }
+        return new SensorProperties(internalProp.sensorId, internalProp.sensorStrength,
+                componentInfo);
     }
 }
diff --git a/core/java/android/hardware/biometrics/SensorPropertiesInternal.java b/core/java/android/hardware/biometrics/SensorPropertiesInternal.java
index 909f456..17b2abf 100644
--- a/core/java/android/hardware/biometrics/SensorPropertiesInternal.java
+++ b/core/java/android/hardware/biometrics/SensorPropertiesInternal.java
@@ -20,6 +20,9 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * The base class containing all modality-agnostic information. This is a superset of the
  * {@link android.hardware.biometrics.common.CommonProps}, and provides backwards-compatible
@@ -31,21 +34,23 @@
     public final int sensorId;
     @SensorProperties.Strength public final int sensorStrength;
     public final int maxEnrollmentsPerUser;
+    @NonNull public final List<ComponentInfoInternal> componentInfo;
     public final boolean resetLockoutRequiresHardwareAuthToken;
     public final boolean resetLockoutRequiresChallenge;
 
     public static SensorPropertiesInternal from(@NonNull SensorPropertiesInternal prop) {
         return new SensorPropertiesInternal(prop.sensorId, prop.sensorStrength,
-                prop.maxEnrollmentsPerUser, prop.resetLockoutRequiresHardwareAuthToken,
-                prop.resetLockoutRequiresChallenge);
+                prop.maxEnrollmentsPerUser, prop.componentInfo,
+                prop.resetLockoutRequiresHardwareAuthToken, prop.resetLockoutRequiresChallenge);
     }
 
     protected SensorPropertiesInternal(int sensorId, @SensorProperties.Strength int sensorStrength,
-            int maxEnrollmentsPerUser, boolean resetLockoutRequiresHardwareAuthToken,
-            boolean resetLockoutRequiresChallenge) {
+            int maxEnrollmentsPerUser, @NonNull List<ComponentInfoInternal> componentInfo,
+            boolean resetLockoutRequiresHardwareAuthToken, boolean resetLockoutRequiresChallenge) {
         this.sensorId = sensorId;
         this.sensorStrength = sensorStrength;
         this.maxEnrollmentsPerUser = maxEnrollmentsPerUser;
+        this.componentInfo = componentInfo;
         this.resetLockoutRequiresHardwareAuthToken = resetLockoutRequiresHardwareAuthToken;
         this.resetLockoutRequiresChallenge = resetLockoutRequiresChallenge;
     }
@@ -54,6 +59,8 @@
         sensorId = in.readInt();
         sensorStrength = in.readInt();
         maxEnrollmentsPerUser = in.readInt();
+        componentInfo = new ArrayList<>();
+        in.readList(componentInfo, ComponentInfoInternal.class.getClassLoader());
         resetLockoutRequiresHardwareAuthToken = in.readBoolean();
         resetLockoutRequiresChallenge = in.readBoolean();
     }
@@ -81,13 +88,23 @@
         dest.writeInt(sensorId);
         dest.writeInt(sensorStrength);
         dest.writeInt(maxEnrollmentsPerUser);
+        dest.writeList(componentInfo);
         dest.writeBoolean(resetLockoutRequiresHardwareAuthToken);
         dest.writeBoolean(resetLockoutRequiresChallenge);
     }
 
     @Override
     public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("[ ");
+        for (ComponentInfoInternal info : componentInfo) {
+            sb.append("[").append(info.toString());
+            sb.append("] ");
+        }
+        sb.append("]");
+
         return "ID: " + sensorId + ", Strength: " + sensorStrength
-                + ", MaxEnrollmentsPerUser: " + maxEnrollmentsPerUser;
+                + ", MaxEnrollmentsPerUser: " + maxEnrollmentsPerUser
+                + ", ComponentInfo: " + sb.toString();
     }
 }
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index a3c6f2f..b7b1a14 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -2030,7 +2030,9 @@
                 // Tell listeners that the cameras and torch modes are unavailable and schedule a
                 // reconnection to camera service. When camera service is reconnected, the camera
                 // and torch statuses will be updated.
-                for (int i = 0; i < mDeviceStatus.size(); i++) {
+                // Iterate from the end to the beginning befcause onStatusChangedLocked removes
+                // entries from the ArrayMap.
+                for (int i = mDeviceStatus.size() - 1; i >= 0; i--) {
                     String cameraId = mDeviceStatus.keyAt(i);
                     onStatusChangedLocked(ICameraServiceListener.STATUS_NOT_PRESENT, cameraId);
                 }
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 157e333..9ac2ff5 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -3345,7 +3345,7 @@
      * <p>A control for selecting whether optical stabilization (OIS) position
      * information is included in output result metadata.</p>
      * <p>Since optical image stabilization generally involves motion much faster than the duration
-     * of individualq image exposure, multiple OIS samples can be included for a single capture
+     * of individual image exposure, multiple OIS samples can be included for a single capture
      * result. For example, if the OIS reporting operates at 200 Hz, a typical camera operating
      * at 30fps may have 6-7 OIS samples per capture result. This information can be combined
      * with the rolling shutter skew to account for lens motion during image exposure in
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index c0eb068..e7457e7 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -4635,7 +4635,7 @@
      * <p>A control for selecting whether optical stabilization (OIS) position
      * information is included in output result metadata.</p>
      * <p>Since optical image stabilization generally involves motion much faster than the duration
-     * of individualq image exposure, multiple OIS samples can be included for a single capture
+     * of individual image exposure, multiple OIS samples can be included for a single capture
      * result. For example, if the OIS reporting operates at 200 Hz, a typical camera operating
      * at 30fps may have 6-7 OIS samples per capture result. This information can be combined
      * with the rolling shutter skew to account for lens motion during image exposure in
diff --git a/core/java/android/hardware/camera2/MultiResolutionImageReader.java b/core/java/android/hardware/camera2/MultiResolutionImageReader.java
index c592f19..bb3d91d 100644
--- a/core/java/android/hardware/camera2/MultiResolutionImageReader.java
+++ b/core/java/android/hardware/camera2/MultiResolutionImageReader.java
@@ -131,18 +131,10 @@
      * @see
      * android.hardware.camera2.params.MultiResolutionStreamConfigurationMap
      */
-    public static @NonNull MultiResolutionImageReader newInstance(
+    public MultiResolutionImageReader(
             @NonNull Collection<MultiResolutionStreamInfo> streams,
             @Format             int format,
             @IntRange(from = 1) int maxImages) {
-        return new MultiResolutionImageReader(streams, format, maxImages);
-    }
-
-    /**
-     * @hide
-     */
-    protected MultiResolutionImageReader(Collection<MultiResolutionStreamInfo> streams,
-            int format, int maxImages) {
         mFormat = format;
         mMaxImages = maxImages;
 
diff --git a/core/java/android/hardware/camera2/params/MultiResolutionStreamInfo.java b/core/java/android/hardware/camera2/params/MultiResolutionStreamInfo.java
index aa1d1d4..e2e61ad 100644
--- a/core/java/android/hardware/camera2/params/MultiResolutionStreamInfo.java
+++ b/core/java/android/hardware/camera2/params/MultiResolutionStreamInfo.java
@@ -17,6 +17,7 @@
 package android.hardware.camera2.params;
 
 import android.annotation.NonNull;
+import android.annotation.IntRange;
 
 import java.util.Objects;
 
@@ -50,9 +51,22 @@
      * MultiResolutionStreamConfigurationMap#getOutputInfo} or {@link
      * MultiResolutionStreamConfigurationMap#getInputInfo} to obtain them for a particular format
      * instead.</p>
+     *
+     * @param streamWidth The width in pixels of the camera stream
+     * @param streamHeight The height in pixels of the camera stream
+     * @param physicalCameraId The physical camera Id the camera stream is associated with
+     * @throws IllegalArgumentException if the streamWidth or streamHeight is invalid (either zero
+     *                                  or negative).
      */
-    public MultiResolutionStreamInfo(int streamWidth, int streamHeight,
+    public MultiResolutionStreamInfo(@IntRange(from = 1) int streamWidth,
+            @IntRange(from = 1) int streamHeight,
             @NonNull String physicalCameraId) {
+        if (streamWidth <= 0) {
+            throw new IllegalArgumentException("Invalid stream width " + streamWidth);
+        }
+        if (streamHeight <= 0) {
+            throw new IllegalArgumentException("Invalid stream height " + streamHeight);
+        }
         mStreamWidth = streamWidth;
         mStreamHeight = streamHeight;
         mPhysicalCameraId = physicalCameraId;
@@ -61,14 +75,14 @@
     /**
      * The width of this particular image buffer stream in pixels.
      */
-    public int getWidth() {
+    public @IntRange(from = 1) int getWidth() {
         return mStreamWidth;
     }
 
     /**
      * The height of this particular image buffer stream in pixels.
      */
-    public int getHeight() {
+    public @IntRange(from = 1) int getHeight() {
         return mStreamHeight;
     }
 
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 2c3e7f1..6dd6744 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -20,6 +20,7 @@
 
 import android.Manifest;
 import android.annotation.IntDef;
+import android.annotation.LongDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -376,6 +377,43 @@
     @TestApi
     public static final int SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS = 2;
 
+    /**
+     * @hide
+     */
+    @LongDef(flag = true, prefix = {"EVENT_FLAG_"}, value = {
+            EVENT_FLAG_DISPLAY_ADDED,
+            EVENT_FLAG_DISPLAY_CHANGED,
+            EVENT_FLAG_DISPLAY_REMOVED,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface EventsMask {}
+
+    /**
+     * Event type for when a new display is added.
+     *
+     * @see #registerDisplayListener(DisplayListener, Handler, long)
+     *
+     * @hide
+     */
+    public static final long EVENT_FLAG_DISPLAY_ADDED = 1L << 0;
+
+    /**
+     * Event type for when a display is removed.
+     *
+     * @see #registerDisplayListener(DisplayListener, Handler, long)
+     *
+     * @hide
+     */
+    public static final long EVENT_FLAG_DISPLAY_REMOVED = 1L << 1;
+
+    /**
+     * Event type for when a display is changed.
+     *
+     * @see #registerDisplayListener(DisplayListener, Handler, long)
+     *
+     * @hide
+     */
+    public static final long EVENT_FLAG_DISPLAY_CHANGED = 1L << 2;
 
     /** @hide */
     public DisplayManager(Context context) {
@@ -486,7 +524,7 @@
     }
 
     /**
-     * Registers an display listener to receive notifications about when
+     * Registers a display listener to receive notifications about when
      * displays are added, removed or changed.
      *
      * @param listener The listener to register.
@@ -496,7 +534,29 @@
      * @see #unregisterDisplayListener
      */
     public void registerDisplayListener(DisplayListener listener, Handler handler) {
-        mGlobal.registerDisplayListener(listener, handler);
+        registerDisplayListener(listener, handler, EVENT_FLAG_DISPLAY_ADDED
+                | EVENT_FLAG_DISPLAY_CHANGED | EVENT_FLAG_DISPLAY_REMOVED);
+    }
+
+    /**
+     * Registers a display listener to receive notifications about given display event types.
+     *
+     * @param listener The listener to register.
+     * @param handler The handler on which the listener should be invoked, or null
+     * if the listener should be invoked on the calling thread's looper.
+     * @param eventsMask A bitmask of the event types for which this listener is subscribed.
+     *
+     * @see #EVENT_FLAG_DISPLAY_ADDED
+     * @see #EVENT_FLAG_DISPLAY_CHANGED
+     * @see #EVENT_FLAG_DISPLAY_REMOVED
+     * @see #registerDisplayListener(DisplayListener, Handler)
+     * @see #unregisterDisplayListener
+     *
+     * @hide
+     */
+    public void registerDisplayListener(@NonNull DisplayListener listener,
+            @Nullable Handler handler, @EventsMask long eventsMask) {
+        mGlobal.registerDisplayListener(listener, handler, eventsMask);
     }
 
     /**
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 60fe582..fd0431c5 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -16,6 +16,9 @@
 
 package android.hardware.display;
 
+import static android.hardware.display.DisplayManager.EventsMask;
+
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.PropertyInvalidatedCache;
@@ -42,6 +45,10 @@
 import android.view.DisplayInfo;
 import android.view.Surface;
 
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -66,6 +73,14 @@
     // orientation change before the display info cache has actually been invalidated.
     private static final boolean USE_CACHE = false;
 
+    @IntDef(prefix = {"SWITCHING_TYPE_"}, value = {
+            EVENT_DISPLAY_ADDED,
+            EVENT_DISPLAY_CHANGED,
+            EVENT_DISPLAY_REMOVED,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DisplayEvent {}
+
     public static final int EVENT_DISPLAY_ADDED = 1;
     public static final int EVENT_DISPLAY_CHANGED = 2;
     public static final int EVENT_DISPLAY_REMOVED = 3;
@@ -81,16 +96,17 @@
     private final IDisplayManager mDm;
 
     private DisplayManagerCallback mCallback;
-    private final ArrayList<DisplayListenerDelegate> mDisplayListeners =
-            new ArrayList<DisplayListenerDelegate>();
+    private @EventsMask long mRegisteredEventsMask = 0;
+    private final ArrayList<DisplayListenerDelegate> mDisplayListeners = new ArrayList<>();
 
-    private final SparseArray<DisplayInfo> mDisplayInfoCache = new SparseArray<DisplayInfo>();
+    private final SparseArray<DisplayInfo> mDisplayInfoCache = new SparseArray<>();
     private final ColorSpace mWideColorSpace;
     private int[] mDisplayIdCache;
 
     private int mWifiDisplayScanNestCount;
 
-    private DisplayManagerGlobal(IDisplayManager dm) {
+    @VisibleForTesting
+    public DisplayManagerGlobal(IDisplayManager dm) {
         mDm = dm;
         try {
             mWideColorSpace =
@@ -274,18 +290,25 @@
      * If that is still null, a runtime exception will be thrown.
      */
     public void registerDisplayListener(@NonNull DisplayListener listener,
-            @Nullable Handler handler) {
+            @Nullable Handler handler, @EventsMask long eventsMask) {
         if (listener == null) {
             throw new IllegalArgumentException("listener must not be null");
         }
 
+        if (eventsMask == 0) {
+            throw new IllegalArgumentException("The set of events to listen to must not be empty.");
+        }
+
         synchronized (mLock) {
             int index = findDisplayListenerLocked(listener);
             if (index < 0) {
                 Looper looper = getLooperForHandler(handler);
-                mDisplayListeners.add(new DisplayListenerDelegate(listener, looper));
+                mDisplayListeners.add(new DisplayListenerDelegate(listener, looper, eventsMask));
                 registerCallbackIfNeededLocked();
+            } else {
+                mDisplayListeners.get(index).setEventsMask(eventsMask);
             }
+            updateCallbackIfNeededLocked();
         }
     }
 
@@ -300,6 +323,7 @@
                 DisplayListenerDelegate d = mDisplayListeners.get(index);
                 d.clearEvents();
                 mDisplayListeners.remove(index);
+                updateCallbackIfNeededLocked();
             }
         }
     }
@@ -325,18 +349,36 @@
         return -1;
     }
 
+    @EventsMask
+    private int calculateEventsMaskLocked() {
+        int mask = 0;
+        final int numListeners = mDisplayListeners.size();
+        for (int i = 0; i < numListeners; i++) {
+            mask |= mDisplayListeners.get(i).mEventsMask;
+        }
+        return mask;
+    }
+
     private void registerCallbackIfNeededLocked() {
         if (mCallback == null) {
             mCallback = new DisplayManagerCallback();
+            updateCallbackIfNeededLocked();
+        }
+    }
+
+    private void updateCallbackIfNeededLocked() {
+        int mask = calculateEventsMaskLocked();
+        if (mask != mRegisteredEventsMask) {
             try {
-                mDm.registerCallback(mCallback);
+                mDm.registerCallbackWithEventMask(mCallback, mask);
+                mRegisteredEventsMask = mask;
             } catch (RemoteException ex) {
                 throw ex.rethrowFromSystemServer();
             }
         }
     }
 
-    private void handleDisplayEvent(int displayId, int event) {
+    private void handleDisplayEvent(int displayId, @DisplayEvent int event) {
         synchronized (mLock) {
             if (USE_CACHE) {
                 mDisplayInfoCache.remove(displayId);
@@ -754,7 +796,7 @@
 
     private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub {
         @Override
-        public void onDisplayEvent(int displayId, int event) {
+        public void onDisplayEvent(int displayId, @DisplayEvent int event) {
             if (DEBUG) {
                 Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + event);
             }
@@ -764,13 +806,16 @@
 
     private static final class DisplayListenerDelegate extends Handler {
         public final DisplayListener mListener;
+        public long mEventsMask;
 
-        DisplayListenerDelegate(DisplayListener listener, @NonNull Looper looper) {
+        DisplayListenerDelegate(DisplayListener listener, @NonNull Looper looper,
+                @EventsMask long eventsMask) {
             super(looper, null, true /*async*/);
             mListener = listener;
+            mEventsMask = eventsMask;
         }
 
-        public void sendDisplayEvent(int displayId, int event) {
+        public void sendDisplayEvent(int displayId, @DisplayEvent int event) {
             Message msg = obtainMessage(event, displayId, 0);
             sendMessage(msg);
         }
@@ -779,17 +824,27 @@
             removeCallbacksAndMessages(null);
         }
 
+        public synchronized void setEventsMask(@EventsMask long newEventsMask) {
+            mEventsMask = newEventsMask;
+        }
+
         @Override
-        public void handleMessage(Message msg) {
+        public synchronized void handleMessage(Message msg) {
             switch (msg.what) {
                 case EVENT_DISPLAY_ADDED:
-                    mListener.onDisplayAdded(msg.arg1);
+                    if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_ADDED) != 0) {
+                        mListener.onDisplayAdded(msg.arg1);
+                    }
                     break;
                 case EVENT_DISPLAY_CHANGED:
-                    mListener.onDisplayChanged(msg.arg1);
+                    if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_CHANGED) != 0) {
+                        mListener.onDisplayChanged(msg.arg1);
+                    }
                     break;
                 case EVENT_DISPLAY_REMOVED:
-                    mListener.onDisplayRemoved(msg.arg1);
+                    if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_REMOVED) != 0) {
+                        mListener.onDisplayRemoved(msg.arg1);
+                    }
                     break;
             }
         }
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index ff8a720..dee9144 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -38,6 +38,7 @@
     boolean isUidPresentOnDisplay(int uid, int displayId);
 
     void registerCallback(in IDisplayManagerCallback callback);
+    void registerCallbackWithEventMask(in IDisplayManagerCallback callback, long eventsMask);
 
     // Requires CONFIGURE_WIFI_DISPLAY permission.
     // The process must have previously registered a callback.
diff --git a/core/java/android/hardware/face/FaceSensorProperties.java b/core/java/android/hardware/face/FaceSensorProperties.java
index e61d931..f613127 100644
--- a/core/java/android/hardware/face/FaceSensorProperties.java
+++ b/core/java/android/hardware/face/FaceSensorProperties.java
@@ -16,25 +16,77 @@
 
 package android.hardware.face;
 
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.SensorProperties;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Container for face sensor properties.
  * @hide
  */
 public class FaceSensorProperties extends SensorProperties {
+    /**
+     * @hide
+     */
+    public static final int TYPE_UNKNOWN = 0;
+
+    /**
+     * @hide
+     */
+    public static final int TYPE_RGB = 1;
+
+    /**
+     * @hide
+     */
+    public static final int TYPE_IR = 2;
+
+    /**
+     * @hide
+     */
+    @IntDef({TYPE_UNKNOWN,
+            TYPE_RGB,
+            TYPE_IR})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SensorType {}
+
+    @FaceSensorProperties.SensorType
+    final int mSensorType;
 
     /**
      * @hide
      */
     public static FaceSensorProperties from(FaceSensorPropertiesInternal internalProp) {
-        return new FaceSensorProperties(internalProp.sensorId, internalProp.sensorStrength);
+        final List<ComponentInfo> componentInfo = new ArrayList<>();
+        for (ComponentInfoInternal internalComp : internalProp.componentInfo) {
+            componentInfo.add(ComponentInfo.from(internalComp));
+        }
+        return new FaceSensorProperties(internalProp.sensorId,
+                internalProp.sensorStrength,
+                componentInfo,
+                internalProp.sensorType);
     }
     /**
      * @hide
      */
-    public FaceSensorProperties(int sensorId, int sensorStrength) {
-        super(sensorId, sensorStrength);
+    public FaceSensorProperties(int sensorId, int sensorStrength,
+            @NonNull List<ComponentInfo> componentInfo,
+            @FaceSensorProperties.SensorType int sensorType) {
+        super(sensorId, sensorStrength, componentInfo);
+        mSensorType = sensorType;
     }
 
+    /**
+     * @hide
+     * @return The sensor's type.
+     */
+    @FaceSensorProperties.SensorType
+    public int getSensorType() {
+        return mSensorType;
+    }
 }
diff --git a/core/java/android/hardware/face/FaceSensorPropertiesInternal.java b/core/java/android/hardware/face/FaceSensorPropertiesInternal.java
index 34cbcb4..44dffb2 100644
--- a/core/java/android/hardware/face/FaceSensorPropertiesInternal.java
+++ b/core/java/android/hardware/face/FaceSensorPropertiesInternal.java
@@ -16,16 +16,25 @@
 
 package android.hardware.face;
 
+import android.annotation.NonNull;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.SensorProperties;
 import android.hardware.biometrics.SensorPropertiesInternal;
 import android.os.Parcel;
 
+import java.util.List;
+
 /**
  * Container for face sensor properties.
  * @hide
  */
 public class FaceSensorPropertiesInternal extends SensorPropertiesInternal {
     /**
+     * See {@link FaceSensorProperties.SensorType}.
+     */
+    public final @FaceSensorProperties.SensorType int sensorType;
+
+    /**
      * True if the sensor is able to perform generic face detection, without running the
      * matching algorithm, and without affecting the lockout counter.
      */
@@ -40,18 +49,21 @@
      * Initializes SensorProperties with specified values
      */
     public FaceSensorPropertiesInternal(int sensorId, @SensorProperties.Strength int strength,
-            int maxEnrollmentsPerUser, boolean supportsFaceDetection,
+            int maxEnrollmentsPerUser, @NonNull List<ComponentInfoInternal> componentInfo,
+            @FaceSensorProperties.SensorType int sensorType, boolean supportsFaceDetection,
             boolean supportsSelfIllumination, boolean resetLockoutRequiresChallenge) {
         // resetLockout is managed by the HAL and requires a HardwareAuthToken for all face
         // HAL interfaces (IBiometricsFace@1.0 HIDL and IFace@1.0 AIDL).
-        super(sensorId, strength, maxEnrollmentsPerUser,
-                true /* resetLockoutRequiresHardwareAuthToken */, resetLockoutRequiresChallenge);
+        super(sensorId, strength, maxEnrollmentsPerUser, componentInfo,
+            true /* resetLockoutRequiresHardwareAuthToken */, resetLockoutRequiresChallenge);
+        this.sensorType = sensorType;
         this.supportsFaceDetection = supportsFaceDetection;
         this.supportsSelfIllumination = supportsSelfIllumination;
     }
 
     protected FaceSensorPropertiesInternal(Parcel in) {
         super(in);
+        sensorType = in.readInt();
         supportsFaceDetection = in.readBoolean();
         supportsSelfIllumination = in.readBoolean();
     }
@@ -77,12 +89,13 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         super.writeToParcel(dest, flags);
+        dest.writeInt(sensorType);
         dest.writeBoolean(supportsFaceDetection);
         dest.writeBoolean(supportsSelfIllumination);
     }
 
     @Override
     public String toString() {
-        return "ID: " + sensorId + ", Strength: " + sensorStrength;
+        return "ID: " + sensorId + ", Strength: " + sensorStrength + ", Type: " + sensorType;
     }
 }
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index 6e7c701..0b44150 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -59,7 +59,7 @@
     // startPreparedClient().
     void prepareForAuthentication(int sensorId, boolean requireConfirmation, IBinder token, long operationId,
             int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
-            int cookie);
+            int cookie, boolean allowBackgroundAuthentication);
 
     // Starts authentication with the previously prepared client.
     void startPreparedClient(int sensorId, int cookie);
diff --git a/core/java/android/hardware/fingerprint/FingerprintSensorProperties.java b/core/java/android/hardware/fingerprint/FingerprintSensorProperties.java
index 684d7d9..71b705f 100644
--- a/core/java/android/hardware/fingerprint/FingerprintSensorProperties.java
+++ b/core/java/android/hardware/fingerprint/FingerprintSensorProperties.java
@@ -17,10 +17,14 @@
 package android.hardware.fingerprint;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.SensorProperties;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Container for fingerprint sensor properties.
@@ -77,8 +81,13 @@
      */
     public static FingerprintSensorProperties from(
             FingerprintSensorPropertiesInternal internalProp) {
+        final List<ComponentInfo> componentInfo = new ArrayList<>();
+        for (ComponentInfoInternal internalComp : internalProp.componentInfo) {
+            componentInfo.add(ComponentInfo.from(internalComp));
+        }
         return new FingerprintSensorProperties(internalProp.sensorId,
                 internalProp.sensorStrength,
+                componentInfo,
                 internalProp.sensorType);
     }
 
@@ -86,8 +95,8 @@
      * @hide
      */
     public FingerprintSensorProperties(int sensorId, int sensorStrength,
-            @SensorType int sensorType) {
-        super(sensorId, sensorStrength);
+            @NonNull List<ComponentInfo> componentInfo, @SensorType int sensorType) {
+        super(sensorId, sensorStrength, componentInfo);
         mSensorType = sensorType;
     }
 
diff --git a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
index adc61a7..58f6e62 100644
--- a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
+++ b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
@@ -21,10 +21,13 @@
 
 import android.annotation.NonNull;
 import android.content.Context;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.SensorProperties;
 import android.hardware.biometrics.SensorPropertiesInternal;
 import android.os.Parcel;
 
+import java.util.List;
+
 /**
  * Container for fingerprint sensor properties.
  * @hide
@@ -59,6 +62,7 @@
 
     public FingerprintSensorPropertiesInternal(int sensorId,
             @SensorProperties.Strength int strength, int maxEnrollmentsPerUser,
+            @NonNull List<ComponentInfoInternal> componentInfo,
             @FingerprintSensorProperties.SensorType int sensorType,
             boolean resetLockoutRequiresHardwareAuthToken, int sensorLocationX, int sensorLocationY,
             int sensorRadius) {
@@ -66,8 +70,8 @@
         // required as it can only be generated/attested/verified by TEE components.
         // IFingerprint@1.0 handles lockout below the HAL, but does not require a challenge. See
         // the HAL interface for more details.
-        super(sensorId, strength, maxEnrollmentsPerUser, resetLockoutRequiresHardwareAuthToken,
-                false /* resetLockoutRequiresChallenge */);
+        super(sensorId, strength, maxEnrollmentsPerUser, componentInfo,
+            resetLockoutRequiresHardwareAuthToken, false /* resetLockoutRequiresChallenge */);
         this.sensorType = sensorType;
         this.sensorLocationX = sensorLocationX;
         this.sensorLocationY = sensorLocationY;
@@ -79,10 +83,11 @@
      */
     public FingerprintSensorPropertiesInternal(int sensorId,
             @SensorProperties.Strength int strength, int maxEnrollmentsPerUser,
+            @NonNull List<ComponentInfoInternal> componentInfo,
             @FingerprintSensorProperties.SensorType int sensorType,
             boolean resetLockoutRequiresHardwareAuthToken) {
         // TODO(b/179175438): Value should be provided from the HAL
-        this(sensorId, strength, maxEnrollmentsPerUser, sensorType,
+        this(sensorId, strength, maxEnrollmentsPerUser, componentInfo, sensorType,
                 resetLockoutRequiresHardwareAuthToken, 540 /* sensorLocationX */,
                 1636 /* sensorLocationY */, 130 /* sensorRadius */);
     }
@@ -94,10 +99,11 @@
     // TODO(b/179175438): Remove this constructor once all HALs move to AIDL.
     public FingerprintSensorPropertiesInternal(@NonNull Context context, int sensorId,
             @SensorProperties.Strength int strength, int maxEnrollmentsPerUser,
+            @NonNull List<ComponentInfoInternal> componentInfo,
             @FingerprintSensorProperties.SensorType int sensorType,
             boolean resetLockoutRequiresHardwareAuthToken) {
-        super(sensorId, strength, maxEnrollmentsPerUser, resetLockoutRequiresHardwareAuthToken,
-                false /* resetLockoutRequiresChallenge */);
+        super(sensorId, strength, maxEnrollmentsPerUser, componentInfo,
+            resetLockoutRequiresHardwareAuthToken, false /* resetLockoutRequiresChallenge */);
         this.sensorType = sensorType;
 
         int[] props = context.getResources().getIntArray(
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 054c0d0..469e87e2 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -62,7 +62,8 @@
     // by BiometricService. To start authentication after the clients are ready, use
     // startPreparedClient().
     void prepareForAuthentication(int sensorId, IBinder token, long operationId, int userId,
-            IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie);
+            IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie,
+            boolean allowBackgroundAuthentication);
 
     // Starts authentication with the previously prepared client.
     void startPreparedClient(int sensorId, int cookie);
diff --git a/core/java/android/hardware/fingerprint/IUdfpsHbmListener.aidl b/core/java/android/hardware/fingerprint/IUdfpsHbmListener.aidl
new file mode 100644
index 0000000..b79d6e0
--- /dev/null
+++ b/core/java/android/hardware/fingerprint/IUdfpsHbmListener.aidl
@@ -0,0 +1,47 @@
+/*
+ * 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.fingerprint;
+
+/**
+ * A listener for the high-brightness mode (HBM) transitions. This allows other components to
+ * perform certain actions when the HBM is toggled on or off. For example, a display manager
+ * implementation can subscribe to these events from UdfpsController and adjust the display's
+ * refresh rate when the HBM is enabled.
+ *
+ * @hide
+ */
+oneway interface IUdfpsHbmListener {
+    /**
+     * UdfpsController will call this method when the HBM is enabled.
+     *
+     * @param hbmType The type of HBM that was enabled. See
+     *        {@link com.android.systemui.biometrics.HbmTypes}.
+     * @param displayId The displayId for which the HBM is enabled. See
+     *        {@link android.view.Display#getDisplayId()}.
+     */
+    void onHbmEnabled(int hbmType, int displayId);
+
+    /**
+     * UdfpsController will call this method when the HBM is disabled.
+     *
+     * @param hbmType The type of HBM that was disabled. See
+     *        {@link com.android.systemui.biometrics.HbmTypes}.
+     * @param displayId The displayId for which the HBM is disabled. See
+     *        {@link android.view.Display#getDisplayId()}.
+     */
+    void onHbmDisabled(int hbmType, int displayId);
+}
+
diff --git a/core/java/android/hardware/location/ContextHubClient.java b/core/java/android/hardware/location/ContextHubClient.java
index 49beeb3..21ac71c 100644
--- a/core/java/android/hardware/location/ContextHubClient.java
+++ b/core/java/android/hardware/location/ContextHubClient.java
@@ -146,6 +146,8 @@
      * @return the result of sending the message defined as in ContextHubTransaction.Result
      *
      * @throws NullPointerException if NanoAppMessage is null
+     * @throws SecurityException if this client doesn't have permissions to send a message to the
+     * nanoapp.
      *
      * @see NanoAppMessage
      * @see ContextHubTransaction.Result
diff --git a/core/java/android/hardware/location/ContextHubClientCallback.java b/core/java/android/hardware/location/ContextHubClientCallback.java
index 7e484dd..35d00f0 100644
--- a/core/java/android/hardware/location/ContextHubClientCallback.java
+++ b/core/java/android/hardware/location/ContextHubClientCallback.java
@@ -117,11 +117,10 @@
      * 4) {@link ContextHubClient} performs any cleanup required with the nanoapp
      * 5) Callback invoked with the nanoapp ID and {@link ContextHubManager#AUTHORIZATION_DENIED}.
      *    At this point, any further attempts of communication between the nanoapp and the
-     *    {@link ContextHubClient} will be dropped by the contexthub and a return value of
-     *    {@link ContextHubTransaction#RESULT_FAILED_PERMISSION_DENIED} will be used when calling
-     *    {@link ContextHubClient#sendMessageToNanoApp}. The {@link ContextHubClient} should assume
-     *    no communciation can happen again until {@link ContextHubManager#AUTHORIZATION_GRANTED} is
-     *    received.
+     *    {@link ContextHubClient} will be dropped by the contexthub and a security exception will
+     *    be thrown when calling {@link ContextHubClient#sendMessageToNanoApp}. The
+     *    {@link ContextHubClient} should assume no communciation can happen again until
+     *    {@link ContextHubManager#AUTHORIZATION_GRANTED} is received.
      *
      * @param client the client that is associated with this callback
      * @param nanoAppId the ID of the nanoapp associated with the new
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index eaa8bd4..f69a7d7 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -60,8 +60,8 @@
     private static final String TAG = "ContextHubManager";
 
     /**
-     * An extra containing an int from {@link AuthorizationState} describing the client's
-     * authorization state.
+     * An extra containing one of the {@code AUTHORIZATION_*} constants such as
+     * {@link #AUTHORIZATION_GRANTED} describing the client's authorization state.
      */
     public static final String EXTRA_CLIENT_AUTHORIZATION_STATE =
             "android.hardware.location.extra.CLIENT_AUTHORIZATION_STATE";
diff --git a/core/java/android/hardware/location/ContextHubTransaction.java b/core/java/android/hardware/location/ContextHubTransaction.java
index 86f77c0..d11e0a9 100644
--- a/core/java/android/hardware/location/ContextHubTransaction.java
+++ b/core/java/android/hardware/location/ContextHubTransaction.java
@@ -81,8 +81,7 @@
             RESULT_FAILED_AT_HUB,
             RESULT_FAILED_TIMEOUT,
             RESULT_FAILED_SERVICE_INTERNAL_FAILURE,
-            RESULT_FAILED_HAL_UNAVAILABLE,
-            RESULT_FAILED_PERMISSION_DENIED
+            RESULT_FAILED_HAL_UNAVAILABLE
     })
     public @interface Result {}
     public static final int RESULT_SUCCESS = 0;
@@ -118,11 +117,6 @@
      * Failure mode when the Context Hub HAL was not available.
      */
     public static final int RESULT_FAILED_HAL_UNAVAILABLE = 8;
-    /**
-     * Failure mode when the user of the API doesn't have the required permissions to perform the
-     * operation.
-     */
-    public static final int RESULT_FAILED_PERMISSION_DENIED = 9;
 
     /**
      * A class describing the response for a ContextHubTransaction.
diff --git a/core/java/android/net/INetworkPolicyListener.aidl b/core/java/android/net/INetworkPolicyListener.aidl
index dfb1e99..00c6913 100644
--- a/core/java/android/net/INetworkPolicyListener.aidl
+++ b/core/java/android/net/INetworkPolicyListener.aidl
@@ -25,4 +25,5 @@
     void onUidPoliciesChanged(int uid, int uidPolicies);
     void onSubscriptionOverride(int subId, int overrideMask, int overrideValue, in int[] networkTypes);
     void onSubscriptionPlansChanged(int subId, in SubscriptionPlan[] plans);
+    void onBlockedReasonChanged(int uid, int oldBlockedReason, int newBlockedReason);
 }
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 9bf791b..171c6a2 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -62,6 +62,7 @@
         3 - enabled
     */
     int getRestrictBackgroundByCaller();
+    int getRestrictBackgroundStatus(int uid);
 
     void setDeviceIdleMode(boolean enabled);
     void setWifiMeteredOverride(String networkId, int meteredOverride);
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 6641206..3da1227 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -23,6 +23,7 @@
 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.app.ActivityManager;
@@ -44,6 +45,8 @@
 import android.util.Pair;
 import android.util.Range;
 
+import com.android.internal.util.function.pooled.PooledLambda;
+
 import com.google.android.collect.Sets;
 
 import java.lang.annotation.Retention;
@@ -53,6 +56,7 @@
 import java.util.Iterator;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
 
 /**
  * Manager for creating and modifying network policy rules.
@@ -60,6 +64,7 @@
  * @hide
  */
 @TestApi
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
 @SystemService(Context.NETWORK_POLICY_SERVICE)
 public class NetworkPolicyManager {
 
@@ -198,12 +203,157 @@
     })
     public @interface SubscriptionOverrideMask {}
 
+    /**
+     * Flag to indicate that an app is not subject to any restrictions that could result in its
+     * network access blocked.
+     *
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public static final int BLOCKED_REASON_NONE = 0;
+
+    /**
+     * Flag to indicate that an app is subject to Battery saver restrictions that would
+     * result in its network access being blocked.
+     *
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public static final int BLOCKED_REASON_BATTERY_SAVER = 1 << 0;
+
+    /**
+     * Flag to indicate that an app is subject to Doze restrictions that would
+     * result in its network access being blocked.
+     *
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public static final int BLOCKED_REASON_DOZE = 1 << 1;
+
+    /**
+     * Flag to indicate that an app is subject to App Standby restrictions that would
+     * result in its network access being blocked.
+     *
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public static final int BLOCKED_REASON_APP_STANDBY = 1 << 2;
+
+    /**
+     * Flag to indicate that an app is subject to Restricted mode restrictions that would
+     * result in its network access being blocked.
+     *
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public static final int BLOCKED_REASON_RESTRICTED_MODE = 1 << 3;
+
+    /**
+     * Flag to indicate that an app is subject to Data saver restrictions that would
+     * result in its metered network access being blocked.
+     *
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public static final int BLOCKED_METERED_REASON_DATA_SAVER = 1 << 16;
+
+    /**
+     * Flag to indicate that an app is subject to user restrictions that would
+     * result in its metered network access being blocked.
+     *
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public static final int BLOCKED_METERED_REASON_USER_RESTRICTED = 1 << 17;
+
+    /**
+     * Flag to indicate that an app is subject to Device admin restrictions that would
+     * result in its metered network access being blocked.
+     *
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public static final int BLOCKED_METERED_REASON_ADMIN_DISABLED = 1 << 18;
+
+    /** @hide */
+    public static final int BLOCKED_METERED_REASON_MASK = 0xffff0000;
+
+    /**
+     * Flag to indicate that app is not exempt from any network restrictions.
+     *
+     * @hide
+     */
+    public static final int ALLOWED_REASON_NONE = 0;
+    /**
+     * Flag to indicate that app is exempt from certain network restrictions because of it being a
+     * system component.
+     *
+     * @hide
+     */
+    public static final int ALLOWED_REASON_SYSTEM = 1 << 0;
+    /**
+     * Flag to indicate that app is exempt from certain network restrictions because of it being
+     * in the foreground.
+     *
+     * @hide
+     */
+    public static final int ALLOWED_REASON_FOREGROUND = 1 << 1;
+    /**
+     * Flag to indicate that app is exempt from certain network restrictions because of it being
+     * in the {@code allow-in-power-save} list.
+     *
+     * @hide
+     */
+    public static final int ALLOWED_REASON_POWER_SAVE_ALLOWLIST = 1 << 2;
+    /**
+     * Flag to indicate that app is exempt from certain network restrictions because of it being
+     * in the {@code allow-in-power-save-except-idle} list.
+     *
+     * @hide
+     */
+    public static final int ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST = 1 << 3;
+    /**
+     * Flag to indicate that app is exempt from certain network restrictions because of it holding
+     * certain privileged permissions.
+     *
+     * @hide
+     */
+    public static final int ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS = 1 << 4;
+    /**
+     * Flag to indicate that app is exempt from certain metered network restrictions because user
+     * explicitly exempted it.
+     *
+     * @hide
+     */
+    public static final int ALLOWED_METERED_REASON_USER_EXEMPTED = 1 << 16;
+
+    /** @hide */
+    public static final int ALLOWED_METERED_REASON_MASK = 0xffff0000;
+
+    /**
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, prefix = {"BLOCKED_"}, value = {
+            BLOCKED_REASON_NONE,
+            BLOCKED_REASON_BATTERY_SAVER,
+            BLOCKED_REASON_DOZE,
+            BLOCKED_REASON_APP_STANDBY,
+            BLOCKED_REASON_RESTRICTED_MODE,
+            BLOCKED_METERED_REASON_DATA_SAVER,
+            BLOCKED_METERED_REASON_USER_RESTRICTED,
+            BLOCKED_METERED_REASON_ADMIN_DISABLED,
+    })
+    public @interface BlockedReason {}
+
     private final Context mContext;
     @UnsupportedAppUsage
     private INetworkPolicyManager mService;
 
     private final Map<SubscriptionCallback, SubscriptionCallbackProxy>
-            mCallbackMap = new ConcurrentHashMap<>();
+            mSubscriptionCallbackMap = new ConcurrentHashMap<>();
+    private final Map<NetworkPolicyCallback, NetworkPolicyCallbackProxy>
+            mNetworkPolicyCallbackMap = new ConcurrentHashMap<>();
 
     /** @hide */
     public NetworkPolicyManager(Context context, INetworkPolicyManager service) {
@@ -318,7 +468,7 @@
         }
 
         final SubscriptionCallbackProxy callbackProxy = new SubscriptionCallbackProxy(callback);
-        if (null != mCallbackMap.putIfAbsent(callback, callbackProxy)) {
+        if (null != mSubscriptionCallbackMap.putIfAbsent(callback, callbackProxy)) {
             throw new IllegalArgumentException("Callback is already registered.");
         }
         registerListener(callbackProxy);
@@ -331,7 +481,7 @@
             throw new NullPointerException("Callback cannot be null.");
         }
 
-        final SubscriptionCallbackProxy callbackProxy = mCallbackMap.remove(callback);
+        final SubscriptionCallbackProxy callbackProxy = mSubscriptionCallbackMap.remove(callback);
         if (callbackProxy == null) return;
 
         unregisterListener(callbackProxy);
@@ -379,6 +529,26 @@
     }
 
     /**
+     * Determines if an UID is subject to metered network restrictions while running in background.
+     *
+     * @param uid The UID whose status needs to be checked.
+     * @return {@link ConnectivityManager#RESTRICT_BACKGROUND_STATUS_DISABLED},
+     *         {@link ConnectivityManager##RESTRICT_BACKGROUND_STATUS_ENABLED},
+     *         or {@link ConnectivityManager##RESTRICT_BACKGROUND_STATUS_WHITELISTED} to denote
+     *         the current status of the UID.
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)
+    public int getRestrictBackgroundStatus(int uid) {
+        try {
+            return mService.getRestrictBackgroundStatus(uid);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Override connections to be temporarily marked as either unmetered or congested,
      * along with automatic timeouts if desired.
      *
@@ -460,9 +630,8 @@
      * @param meteredNetwork True if the network is metered.
      * @return true if networking is blocked for the given uid according to current networking
      *         policies.
-     *
-     * @hide
      */
+    @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY)
     public boolean isUidNetworkingBlocked(int uid, boolean meteredNetwork) {
         try {
             return mService.isUidNetworkingBlocked(uid, meteredNetwork);
@@ -501,9 +670,8 @@
      *
      * @param uid The target uid.
      * @return true if the given uid is restricted from doing networking on metered networks.
-     *
-     * @hide
      */
+    @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY)
     public boolean isUidRestrictedOnMeteredNetworks(int uid) {
         try {
             return mService.isUidRestrictedOnMeteredNetworks(uid);
@@ -513,11 +681,15 @@
     }
 
     /**
-     * Get multipath preference for the given network.
+     * Gets a hint on whether it is desirable to use multipath data transfer on the given network.
+     *
+     * @return One of the ConnectivityManager.MULTIPATH_PREFERENCE_* constants.
      *
      * @hide
      */
-    public int getMultipathPreference(Network network) {
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)
+    public int getMultipathPreference(@NonNull Network network) {
         try {
             return mService.getMultipathPreference(network);
         } catch (RemoteException e) {
@@ -689,6 +861,142 @@
         return WifiInfo.sanitizeSsid(ssid);
     }
 
+    /**
+     * Returns whether network access of an UID is blocked or not based on {@code blockedReasons}
+     * corresponding to it.
+     *
+     * {@code blockedReasons} would be a bitwise {@code OR} combination of the
+     * {@code BLOCKED_REASON_*} and/or {@code BLOCKED_METERED_REASON_*} constants.
+     *
+     * @param blockedReasons Value indicating the reasons for why the network access of an UID is
+     *                       blocked. If the value is equal to {@link #BLOCKED_REASON_NONE}, then
+     *                       it indicates that an app's network access is not blocked.
+     * @param meteredNetwork Value indicating whether the network is metered or not.
+     * @return Whether network access is blocked or not.
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public static boolean isUidBlocked(@BlockedReason int blockedReasons, boolean meteredNetwork) {
+        if (blockedReasons == BLOCKED_REASON_NONE) {
+            return false;
+        }
+        final int blockedOnAllNetworksReason = (blockedReasons & ~BLOCKED_METERED_REASON_MASK);
+        if (blockedOnAllNetworksReason != BLOCKED_REASON_NONE) {
+            return true;
+        }
+        if (meteredNetwork) {
+            return blockedReasons != BLOCKED_REASON_NONE;
+        }
+        return false;
+    }
+
+    /**
+     * Returns the {@code string} representation of {@code blockedReasons} argument.
+     *
+     * @param blockedReasons Value indicating the reasons for why the network access of an UID is
+     *                       blocked.
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    @NonNull
+    public static String blockedReasonsToString(@BlockedReason int blockedReasons) {
+        return DebugUtils.flagsToString(NetworkPolicyManager.class, "BLOCKED_", blockedReasons);
+    }
+
+    /**
+     * Register a {@link NetworkPolicyCallback} to listen for changes to network blocked status
+     * of apps.
+     *
+     * Note that when a caller tries to register a new callback, it might replace a previously
+     * registered callback if it is considered equal to the new one, based on the
+     * {@link Object#equals(Object)} check.
+     *
+     * @param executor The {@link Executor} to run the callback on.
+     * @param callback The {@link NetworkPolicyCallback} to be registered.
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY)
+    public void registerNetworkPolicyCallback(@Nullable Executor executor,
+            @NonNull NetworkPolicyCallback callback) {
+        if (callback == null) {
+            throw new NullPointerException("Callback cannot be null.");
+        }
+
+        final NetworkPolicyCallbackProxy callbackProxy = new NetworkPolicyCallbackProxy(
+                executor, callback);
+        registerListener(callbackProxy);
+        mNetworkPolicyCallbackMap.put(callback, callbackProxy);
+    }
+
+    /**
+     * Unregister a previously registered {@link NetworkPolicyCallback}.
+     *
+     * @param callback The {@link NetworkPolicyCallback} to be unregistered.
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY)
+    public void unregisterNetworkPolicyCallback(@NonNull NetworkPolicyCallback callback) {
+        if (callback == null) {
+            throw new NullPointerException("Callback cannot be null.");
+        }
+
+        final NetworkPolicyCallbackProxy callbackProxy = mNetworkPolicyCallbackMap.remove(callback);
+        if (callbackProxy == null) return;
+        unregisterListener(callbackProxy);
+    }
+
+    /**
+     * Interface for the callback to listen for changes to network blocked status of apps.
+     *
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public interface NetworkPolicyCallback {
+        /**
+         * Called when the reason for why the network access of an UID is blocked changes.
+         *
+         * @param uid The UID for which the blocked status changed.
+         * @param blockedReasons Value indicating the reasons for why the network access of an
+         *                       UID is blocked.
+         * @hide
+         */
+        @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+        default void onUidBlockedReasonChanged(int uid, @BlockedReason int blockedReasons) {}
+    }
+
+    /** @hide */
+    public static class NetworkPolicyCallbackProxy extends Listener {
+        private final Executor mExecutor;
+        private final NetworkPolicyCallback mCallback;
+
+        NetworkPolicyCallbackProxy(@Nullable Executor executor,
+                @NonNull NetworkPolicyCallback callback) {
+            mExecutor = executor;
+            mCallback = callback;
+        }
+
+        @Override
+        public void onBlockedReasonChanged(int uid, @BlockedReason int oldBlockedReasons,
+                @BlockedReason int newBlockedReasons) {
+            if (oldBlockedReasons != newBlockedReasons) {
+                dispatchOnUidBlockedReasonChanged(mExecutor, mCallback, uid, newBlockedReasons);
+            }
+        }
+    }
+
+    private static void dispatchOnUidBlockedReasonChanged(@Nullable Executor executor,
+            @NonNull NetworkPolicyCallback callback, int uid, @BlockedReason int blockedReasons) {
+        if (executor == null) {
+            callback.onUidBlockedReasonChanged(uid, blockedReasons);
+        } else {
+            executor.execute(PooledLambda.obtainRunnable(
+                    NetworkPolicyCallback::onUidBlockedReasonChanged,
+                    callback, uid, blockedReasons).recycleOnUse());
+        }
+    }
+
     /** @hide */
     public static class SubscriptionCallback {
         /**
@@ -743,5 +1051,7 @@
         @Override public void onSubscriptionOverride(int subId, int overrideMask,
                 int overrideValue, int[] networkTypes) { }
         @Override public void onSubscriptionPlansChanged(int subId, SubscriptionPlan[] plans) { }
+        @Override public void onBlockedReasonChanged(int uid,
+                int oldBlockedReasons, int newBlockedReasons) { }
     }
 }
diff --git a/core/java/android/net/VpnManager.java b/core/java/android/net/VpnManager.java
index 77754d1..5f65d46 100644
--- a/core/java/android/net/VpnManager.java
+++ b/core/java/android/net/VpnManager.java
@@ -86,13 +86,21 @@
     public static final int TYPE_VPN_LEGACY = 3;
 
     /**
+     * An VPN created by OEM code through other means than {@link VpnService} or {@link VpnManager}.
+     * @hide
+     */
+    @SystemApi(client = MODULE_LIBRARIES)
+    public static final int TYPE_VPN_OEM = 4;
+
+    /**
      * Channel for VPN notifications.
      * @hide
      */
     public static final String NOTIFICATION_CHANNEL_VPN = "VPN";
 
     /** @hide */
-    @IntDef(value = {TYPE_VPN_NONE, TYPE_VPN_SERVICE, TYPE_VPN_PLATFORM, TYPE_VPN_LEGACY})
+    @IntDef(value = {TYPE_VPN_NONE, TYPE_VPN_SERVICE, TYPE_VPN_PLATFORM, TYPE_VPN_LEGACY,
+            TYPE_VPN_OEM})
     @Retention(RetentionPolicy.SOURCE)
     public @interface VpnType {}
 
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index 9f83b21..d4e8e2d 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -52,13 +52,12 @@
  * Network}s.
  *
  * <p>A VCN connection based on this configuration will be brought up dynamically based on device
- * settings, and filed NetworkRequests. Underlying networks will be selected based on the services
- * required by this configuration (as represented by network capabilities), and must be part of the
- * subscription group under which this configuration is registered (see {@link
+ * settings, and filed NetworkRequests. Underlying Networks must provide INTERNET connectivity, and
+ * must be part of the subscription group under which this configuration is registered (see {@link
  * VcnManager#setVcnConfig}).
  *
- * <p>As an abstraction of a cellular network, services that can be provided by a VCN network, or
- * required for underlying networks are limited to services provided by cellular networks:
+ * <p>As an abstraction of a cellular network, services that can be provided by a VCN network are
+ * limited to services provided by cellular networks:
  *
  * <ul>
  *   <li>{@link NetworkCapabilities#NET_CAPABILITY_MMS}
@@ -214,13 +213,6 @@
             checkValidCapability(cap);
         }
 
-        Preconditions.checkArgument(
-                mUnderlyingCapabilities != null && !mUnderlyingCapabilities.isEmpty(),
-                "underlyingCapabilities was null or empty");
-        for (Integer cap : getAllUnderlyingCapabilities()) {
-            checkValidCapability(cap);
-        }
-
         Objects.requireNonNull(mRetryIntervalsMs, "retryIntervalsMs was null");
         validateRetryInterval(mRetryIntervalsMs);
 
@@ -295,7 +287,9 @@
      *
      * @see Builder#addRequiredUnderlyingCapability(int)
      * @see Builder#removeRequiredUnderlyingCapability(int)
+     * @hide
      */
+    // TODO(b/182219992): Remove, and add when per-transport capabilities are supported
     @NonNull
     public int[] getRequiredUnderlyingCapabilities() {
         // Sorted set guarantees ordering
@@ -470,7 +464,9 @@
          * @return this {@link Builder} instance, for chaining
          * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying
          *     networks
+         * @hide
          */
+        // TODO(b/182219992): Remove, and add when per-transport capabilities are supported
         @NonNull
         public Builder addRequiredUnderlyingCapability(
                 @VcnSupportedCapability int underlyingCapability) {
@@ -492,7 +488,9 @@
          * @return this {@link Builder} instance, for chaining
          * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying
          *     networks
+         * @hide
          */
+        // TODO(b/182219992): Remove, and add when per-transport capabilities are supported
         @NonNull
         @SuppressLint("BuilderSetStyle") // For consistency with NetCaps.Builder add/removeCap
         public Builder removeRequiredUnderlyingCapability(
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index 062438c..b73fdbf 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -448,7 +448,7 @@
          * @param networkCapabilities an array of NetworkCapabilities.NET_CAPABILITY_* capabilities
          *     for the Gateway Connection that encountered the error, for identification purposes.
          *     These will be a sorted list with no duplicates and will match {@link
-         *     VcnGatewayConnectionConfig#getRequiredUnderlyingCapabilities()} for one of the {@link
+         *     VcnGatewayConnectionConfig#getExposedCapabilities()} for one of the {@link
          *     VcnGatewayConnectionConfig}s set in the {@link VcnConfig} for this subscription
          *     group.
          * @param errorCode the code to indicate the error that occurred
diff --git a/core/java/android/os/BytesMatcher.java b/core/java/android/os/BytesMatcher.java
index 8537f47..8974c5e 100644
--- a/core/java/android/os/BytesMatcher.java
+++ b/core/java/android/os/BytesMatcher.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.bluetooth.BluetoothUuid;
 import android.net.MacAddress;
+import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.internal.util.HexDump;
@@ -42,207 +43,273 @@
  * @hide
  */
 public class BytesMatcher implements Predicate<byte[]> {
-   private static final String TAG = "BytesMatcher";
+    private static final String TAG = "BytesMatcher";
 
-   private static final char TYPE_ACCEPT = '+';
-   private static final char TYPE_REJECT = '-';
+    private static final char TYPE_EXACT_ACCEPT = '+';
+    private static final char TYPE_EXACT_REJECT = '-';
+    private static final char TYPE_PREFIX_ACCEPT = '⊆';
+    private static final char TYPE_PREFIX_REJECT = '⊈';
 
-   private final ArrayList<Rule> mRules = new ArrayList<>();
+    private final ArrayList<Rule> mRules = new ArrayList<>();
 
-   private static class Rule {
-       public final char type;
-       public final @NonNull byte[] value;
-       public final @Nullable byte[] mask;
+    private static class Rule {
+        public final char type;
+        public final @NonNull byte[] value;
+        public final @Nullable byte[] mask;
 
-       public Rule(char type, @NonNull byte[] value, @Nullable byte[] mask) {
-           if (mask != null && value.length != mask.length) {
-               throw new IllegalArgumentException(
-                       "Expected length " + value.length + " but found " + mask.length);
-           }
-           this.type = type;
-           this.value = value;
-           this.mask = mask;
-       }
+        public Rule(char type, @NonNull byte[] value, @Nullable byte[] mask) {
+            if (mask != null && value.length != mask.length) {
+                throw new IllegalArgumentException(
+                        "Expected length " + value.length + " but found " + mask.length);
+            }
+            this.type = type;
+            this.value = value;
+            this.mask = mask;
+        }
 
-       @Override
-       public String toString() {
-           StringBuilder builder = new StringBuilder();
-           encode(builder);
-           return builder.toString();
-       }
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder();
+            encode(builder);
+            return builder.toString();
+        }
 
-       public void encode(@NonNull StringBuilder builder) {
-           builder.append(type);
-           builder.append(HexDump.toHexString(value));
-           if (mask != null) {
-               builder.append('/');
-               builder.append(HexDump.toHexString(mask));
-           }
-       }
+        public void encode(@NonNull StringBuilder builder) {
+            builder.append(type);
+            builder.append(HexDump.toHexString(value));
+            if (mask != null) {
+                builder.append('/');
+                builder.append(HexDump.toHexString(mask));
+            }
+        }
 
-       public boolean test(@NonNull byte[] value) {
-           if (value.length != this.value.length) {
-               return false;
-           }
-           for (int i = 0; i < this.value.length; i++) {
-               byte local = this.value[i];
-               byte remote = value[i];
-               if (this.mask != null) {
-                   local &= this.mask[i];
-                   remote &= this.mask[i];
-               }
-               if (local != remote) {
-                   return false;
-               }
-           }
-           return true;
-       }
-   }
+        public boolean test(@NonNull byte[] value) {
+            switch (type) {
+                case TYPE_EXACT_ACCEPT:
+                case TYPE_EXACT_REJECT:
+                    if (value.length != this.value.length) {
+                        return false;
+                    }
+                    break;
+                case TYPE_PREFIX_ACCEPT:
+                case TYPE_PREFIX_REJECT:
+                    if (value.length < this.value.length) {
+                        return false;
+                    }
+                    break;
+            }
+            for (int i = 0; i < this.value.length; i++) {
+                byte local = this.value[i];
+                byte remote = value[i];
+                if (this.mask != null) {
+                    local &= this.mask[i];
+                    remote &= this.mask[i];
+                }
+                if (local != remote) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
 
-   /**
-    * Add a rule that will result in {@link #test(byte[])} returning
-    * {@code true} when a value being tested matches it.
-    * <p>
-    * Rules are tested in the order in which they were originally added, which
-    * means a narrow rule can reject a specific value before a later broader
-    * rule might accept that same value, or vice versa.
-    *
-    * @param value to be matched
-    * @param mask to be applied to both values before testing for equality; if
-    *            {@code null} then both values must match exactly
-    */
-   public void addAcceptRule(@NonNull byte[] value, @Nullable byte[] mask) {
-       mRules.add(new Rule(TYPE_ACCEPT, value, mask));
-   }
+    /**
+     * Add a rule that will result in {@link #test(byte[])} returning
+     * {@code true} when a value being tested matches it. This rule will only
+     * match values of the exact same length.
+     * <p>
+     * Rules are tested in the order in which they were originally added, which
+     * means a narrow rule can reject a specific value before a later broader
+     * rule might accept that same value, or vice versa.
+     *
+     * @param value to be matched
+     * @param mask to be applied to both values before testing for equality; if
+     *            {@code null} then both values must match exactly
+     */
+    public void addExactAcceptRule(@NonNull byte[] value, @Nullable byte[] mask) {
+        mRules.add(new Rule(TYPE_EXACT_ACCEPT, value, mask));
+    }
 
-   /**
-    * Add a rule that will result in {@link #test(byte[])} returning
-    * {@code false} when a value being tested matches it.
-    * <p>
-    * Rules are tested in the order in which they were originally added, which
-    * means a narrow rule can reject a specific value before a later broader
-    * rule might accept that same value, or vice versa.
-    *
-    * @param value to be matched
-    * @param mask to be applied to both values before testing for equality; if
-    *            {@code null} then both values must match exactly
-    */
-   public void addRejectRule(@NonNull byte[] value, @Nullable byte[] mask) {
-       mRules.add(new Rule(TYPE_REJECT, value, mask));
-   }
+    /**
+     * Add a rule that will result in {@link #test(byte[])} returning
+     * {@code false} when a value being tested matches it. This rule will only
+     * match values of the exact same length.
+     * <p>
+     * Rules are tested in the order in which they were originally added, which
+     * means a narrow rule can reject a specific value before a later broader
+     * rule might accept that same value, or vice versa.
+     *
+     * @param value to be matched
+     * @param mask to be applied to both values before testing for equality; if
+     *            {@code null} then both values must match exactly
+     */
+    public void addExactRejectRule(@NonNull byte[] value, @Nullable byte[] mask) {
+        mRules.add(new Rule(TYPE_EXACT_REJECT, value, mask));
+    }
 
-   /**
-    * Test if the given {@code ParcelUuid} value matches the set of rules
-    * configured in this matcher.
-    */
-   public boolean testBluetoothUuid(@NonNull ParcelUuid value) {
-       return test(BluetoothUuid.uuidToBytes(value));
-   }
+    /**
+     * Add a rule that will result in {@link #test(byte[])} returning
+     * {@code true} when a value being tested matches it. This rule will match
+     * values of the exact same length or longer.
+     * <p>
+     * Rules are tested in the order in which they were originally added, which
+     * means a narrow rule can reject a specific value before a later broader
+     * rule might accept that same value, or vice versa.
+     *
+     * @param value to be matched
+     * @param mask to be applied to both values before testing for equality; if
+     *            {@code null} then both values must match exactly
+     */
+    public void addPrefixAcceptRule(@NonNull byte[] value, @Nullable byte[] mask) {
+        mRules.add(new Rule(TYPE_PREFIX_ACCEPT, value, mask));
+    }
 
-   /**
-    * Test if the given {@code MacAddress} value matches the set of rules
-    * configured in this matcher.
-    */
-   public boolean testMacAddress(@NonNull MacAddress value) {
-       return test(value.toByteArray());
-   }
+    /**
+     * Add a rule that will result in {@link #test(byte[])} returning
+     * {@code false} when a value being tested matches it. This rule will match
+     * values of the exact same length or longer.
+     * <p>
+     * Rules are tested in the order in which they were originally added, which
+     * means a narrow rule can reject a specific value before a later broader
+     * rule might accept that same value, or vice versa.
+     *
+     * @param value to be matched
+     * @param mask to be applied to both values before testing for equality; if
+     *            {@code null} then both values must match exactly
+     */
+    public void addPrefixRejectRule(@NonNull byte[] value, @Nullable byte[] mask) {
+        mRules.add(new Rule(TYPE_PREFIX_REJECT, value, mask));
+    }
 
-   /**
-    * Test if the given {@code byte[]} value matches the set of rules
-    * configured in this matcher.
-    */
-   @Override
-   public boolean test(@NonNull byte[] value) {
-       return test(value, false);
-   }
+    /**
+     * Test if the given {@code ParcelUuid} value matches the set of rules
+     * configured in this matcher.
+     */
+    public boolean testBluetoothUuid(@NonNull ParcelUuid value) {
+        return test(BluetoothUuid.uuidToBytes(value));
+    }
 
-   /**
-    * Test if the given {@code byte[]} value matches the set of rules
-    * configured in this matcher.
-    */
-   public boolean test(@NonNull byte[] value, boolean defaultValue) {
-       final int size = mRules.size();
-       for (int i = 0; i < size; i++) {
-           final Rule rule = mRules.get(i);
-           if (rule.test(value)) {
-               return (rule.type == TYPE_ACCEPT);
-           }
-       }
-       return defaultValue;
-   }
+    /**
+     * Test if the given {@code MacAddress} value matches the set of rules
+     * configured in this matcher.
+     */
+    public boolean testMacAddress(@NonNull MacAddress value) {
+        return test(value.toByteArray());
+    }
 
-   /**
-    * Encode the given matcher into a human-readable {@link String} which can
-    * be used to transport matchers across device boundaries.
-    * <p>
-    * The human-readable format is an ordered list separated by commas, where
-    * each rule is a {@code +} or {@code -} symbol indicating if the match
-    * should be accepted or rejected, then followed by a hex value and an
-    * optional hex mask. For example, {@code -caff,+cafe/ff00} is a valid
-    * encoded matcher.
-    *
-    * @see #decode(String)
-    */
-   public static @NonNull String encode(@NonNull BytesMatcher matcher) {
-       final StringBuilder builder = new StringBuilder();
-       final int size = matcher.mRules.size();
-       for (int i = 0; i < size; i++) {
-           final Rule rule = matcher.mRules.get(i);
-           rule.encode(builder);
-           builder.append(',');
-       }
-       builder.deleteCharAt(builder.length() - 1);
-       return builder.toString();
-   }
+    /**
+     * Test if the given {@code byte[]} value matches the set of rules
+     * configured in this matcher.
+     */
+    @Override
+    public boolean test(@NonNull byte[] value) {
+        return test(value, false);
+    }
 
-   /**
-    * Decode the given human-readable {@link String} used to transport matchers
-    * across device boundaries.
-    * <p>
-    * The human-readable format is an ordered list separated by commas, where
-    * each rule is a {@code +} or {@code -} symbol indicating if the match
-    * should be accepted or rejected, then followed by a hex value and an
-    * optional hex mask. For example, {@code -caff,+cafe/ff00} is a valid
-    * encoded matcher.
-    *
-    * @see #encode(BytesMatcher)
-    */
-   public static @NonNull BytesMatcher decode(@NonNull String value) {
-       final BytesMatcher matcher = new BytesMatcher();
-       final int length = value.length();
-       for (int i = 0; i < length;) {
-           final char type = value.charAt(i);
+    /**
+     * Test if the given {@code byte[]} value matches the set of rules
+     * configured in this matcher.
+     */
+    public boolean test(@NonNull byte[] value, boolean defaultValue) {
+        final int size = mRules.size();
+        for (int i = 0; i < size; i++) {
+            final Rule rule = mRules.get(i);
+            if (rule.test(value)) {
+                switch (rule.type) {
+                    case TYPE_EXACT_ACCEPT:
+                    case TYPE_PREFIX_ACCEPT:
+                        return true;
+                    case TYPE_EXACT_REJECT:
+                    case TYPE_PREFIX_REJECT:
+                        return false;
+                }
+            }
+        }
+        return defaultValue;
+    }
 
-           int nextRule = value.indexOf(',', i);
-           int nextMask = value.indexOf('/', i);
+    /**
+     * Encode the given matcher into a human-readable {@link String} which can
+     * be used to transport matchers across device boundaries.
+     * <p>
+     * The human-readable format is an ordered list separated by commas, where
+     * each rule is a {@code +} or {@code -} symbol indicating if the match
+     * should be accepted or rejected, then followed by a hex value and an
+     * optional hex mask. For example, {@code -caff,+cafe/ff00} is a valid
+     * encoded matcher.
+     *
+     * @see #decode(String)
+     */
+    public static @NonNull String encode(@NonNull BytesMatcher matcher) {
+        final StringBuilder builder = new StringBuilder();
+        final int size = matcher.mRules.size();
+        for (int i = 0; i < size; i++) {
+            final Rule rule = matcher.mRules.get(i);
+            rule.encode(builder);
+            builder.append(',');
+        }
+        if (builder.length() > 0) {
+            builder.deleteCharAt(builder.length() - 1);
+        }
+        return builder.toString();
+    }
 
-           if (nextRule == -1) nextRule = length;
-           if (nextMask > nextRule) nextMask = -1;
+    /**
+     * Decode the given human-readable {@link String} used to transport matchers
+     * across device boundaries.
+     * <p>
+     * The human-readable format is an ordered list separated by commas, where
+     * each rule is a {@code +} or {@code -} symbol indicating if the match
+     * should be accepted or rejected, then followed by a hex value and an
+     * optional hex mask. For example, {@code -caff,+cafe/ff00} is a valid
+     * encoded matcher.
+     *
+     * @see #encode(BytesMatcher)
+     */
+    public static @NonNull BytesMatcher decode(@Nullable String value) {
+        final BytesMatcher matcher = new BytesMatcher();
+        if (TextUtils.isEmpty(value)) return matcher;
 
-           final byte[] ruleValue;
-           final byte[] ruleMask;
-           if (nextMask >= 0) {
-               ruleValue = HexDump.hexStringToByteArray(value.substring(i + 1, nextMask));
-               ruleMask = HexDump.hexStringToByteArray(value.substring(nextMask + 1, nextRule));
-           } else {
-               ruleValue = HexDump.hexStringToByteArray(value.substring(i + 1, nextRule));
-               ruleMask = null;
-           }
+        final int length = value.length();
+        for (int i = 0; i < length;) {
+            final char type = value.charAt(i);
 
-           switch (type) {
-               case TYPE_ACCEPT:
-                   matcher.addAcceptRule(ruleValue, ruleMask);
-                   break;
-               case TYPE_REJECT:
-                   matcher.addRejectRule(ruleValue, ruleMask);
-                   break;
-               default:
-                   Log.w(TAG, "Ignoring unknown type " + type);
-                   break;
-           }
+            int nextRule = value.indexOf(',', i);
+            int nextMask = value.indexOf('/', i);
 
-           i = nextRule + 1;
-       }
-       return matcher;
-   }
+            if (nextRule == -1) nextRule = length;
+            if (nextMask > nextRule) nextMask = -1;
+
+            final byte[] ruleValue;
+            final byte[] ruleMask;
+            if (nextMask >= 0) {
+                ruleValue = HexDump.hexStringToByteArray(value.substring(i + 1, nextMask));
+                ruleMask = HexDump.hexStringToByteArray(value.substring(nextMask + 1, nextRule));
+            } else {
+                ruleValue = HexDump.hexStringToByteArray(value.substring(i + 1, nextRule));
+                ruleMask = null;
+            }
+
+            switch (type) {
+                case TYPE_EXACT_ACCEPT:
+                    matcher.addExactAcceptRule(ruleValue, ruleMask);
+                    break;
+                case TYPE_EXACT_REJECT:
+                    matcher.addExactRejectRule(ruleValue, ruleMask);
+                    break;
+                case TYPE_PREFIX_ACCEPT:
+                    matcher.addPrefixAcceptRule(ruleValue, ruleMask);
+                    break;
+                case TYPE_PREFIX_REJECT:
+                    matcher.addPrefixRejectRule(ruleValue, ruleMask);
+                    break;
+                default:
+                    Log.w(TAG, "Ignoring unknown type " + type);
+                    break;
+            }
+
+            i = nextRule + 1;
+        }
+        return matcher;
+    }
 }
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index ab1f688..bf859d4 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -229,6 +229,12 @@
     public static final int FSVERITY_CERT_UID = 1075;
 
     /**
+     * GID that gives access to USB OTG (unreliable) volumes on /mnt/media_rw/<vol name>
+     * @hide
+     */
+    public static final int EXTERNAL_STORAGE_GID = 1077;
+
+    /**
      * GID that gives write access to app-private data directories on external
      * storage (used on devices without sdcardfs only).
      * @hide
diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java
index 82c4c71..54905ec 100644
--- a/core/java/android/os/storage/StorageManagerInternal.java
+++ b/core/java/android/os/storage/StorageManagerInternal.java
@@ -39,6 +39,17 @@
     public abstract int getExternalStorageMountMode(int uid, String packageName);
 
     /**
+     * Checks whether the {@code packageName} with {@code uid} has full external storage access via
+     * the {@link MANAGE_EXTERNAL_STORAGE} permission.
+     *
+     * @param uid the UID for which to check access.
+     * @param packageName the package in the UID for making the call.
+     * @return whether the {@code packageName} has full external storage access.
+     * Returns {@code true} if it has access, {@code false} otherwise.
+     */
+    public abstract boolean hasExternalStorageAccess(int uid, String packageName);
+
+    /**
      * A listener for reset events in the StorageManagerService.
      */
     public interface ResetListener {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 52bc39c..52517b0 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -433,6 +433,20 @@
             "android.settings.REQUEST_SCHEDULE_EXACT_ALARM";
 
     /**
+     * Activity Action: Show settings to allow configuration of
+     * {@link Manifest.permission#MANAGE_MEDIA} 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: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_REQUEST_MANAGE_MEDIA =
+            "android.settings.REQUEST_MANAGE_MEDIA";
+
+    /**
      * 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
@@ -7037,6 +7051,15 @@
             "enabled_accessibility_services";
 
         /**
+         * List of the notified non-accessibility category accessibility services.
+         *
+         * @hide
+         */
+        @Readable
+        public static final String NOTIFIED_NON_ACCESSIBILITY_CATEGORY_SERVICES =
+                "notified_non_accessibility_category_services";
+
+        /**
          * List of the accessibility services to which the user has granted
          * permission to put the device into touch exploration mode.
          *
@@ -15783,6 +15806,7 @@
          * 1: Enabled (All apps will receive the new rules)
          * @hide
          */
+        @Readable
         public static final String BACKPORT_S_NOTIF_RULES = "backport_s_notif_rules";
 
         /**
@@ -15826,6 +15850,7 @@
          *
          * @hide
          */
+        @Readable
         public static final String BLOCK_UNTRUSTED_TOUCHES_MODE = "block_untrusted_touches";
 
         /**
@@ -15851,6 +15876,7 @@
          *
          * @hide
          */
+        @Readable
         public static final String MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH =
                 "maximum_obscuring_opacity_for_touch";
 
diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java
index e3d0741..6147c58 100644
--- a/core/java/android/service/autofill/Dataset.java
+++ b/core/java/android/service/autofill/Dataset.java
@@ -107,10 +107,12 @@
     private final ArrayList<AutofillValue> mFieldValues;
     private final ArrayList<RemoteViews> mFieldPresentations;
     private final ArrayList<InlinePresentation> mFieldInlinePresentations;
+    private final ArrayList<InlinePresentation> mFieldInlineTooltipPresentations;
     private final ArrayList<DatasetFieldFilter> mFieldFilters;
     @Nullable private final ClipData mFieldContent;
     private final RemoteViews mPresentation;
     @Nullable private final InlinePresentation mInlinePresentation;
+    @Nullable private final InlinePresentation mInlineTooltipPresentation;
     private final IntentSender mAuthentication;
     @Nullable String mId;
 
@@ -119,10 +121,12 @@
         mFieldValues = builder.mFieldValues;
         mFieldPresentations = builder.mFieldPresentations;
         mFieldInlinePresentations = builder.mFieldInlinePresentations;
+        mFieldInlineTooltipPresentations = builder.mFieldInlineTooltipPresentations;
         mFieldFilters = builder.mFieldFilters;
         mFieldContent = builder.mFieldContent;
         mPresentation = builder.mPresentation;
         mInlinePresentation = builder.mInlinePresentation;
+        mInlineTooltipPresentation = builder.mInlineTooltipPresentation;
         mAuthentication = builder.mAuthentication;
         mId = builder.mId;
     }
@@ -154,6 +158,14 @@
     }
 
     /** @hide */
+    public @Nullable InlinePresentation getFieldInlineTooltipPresentation(int index) {
+        final InlinePresentation inlineTooltipPresentation =
+                mFieldInlineTooltipPresentations.get(index);
+        return inlineTooltipPresentation != null
+                ? inlineTooltipPresentation : mInlineTooltipPresentation;
+    }
+
+    /** @hide */
     public @Nullable DatasetFieldFilter getFilter(int index) {
         return mFieldFilters.get(index);
     }
@@ -209,6 +221,10 @@
         if (mFieldInlinePresentations != null) {
             builder.append(", fieldInlinePresentations=").append(mFieldInlinePresentations.size());
         }
+        if (mFieldInlineTooltipPresentations != null) {
+            builder.append(", fieldInlineTooltipInlinePresentations=").append(
+                    mFieldInlineTooltipPresentations.size());
+        }
         if (mFieldFilters != null) {
             builder.append(", fieldFilters=").append(mFieldFilters.size());
         }
@@ -218,6 +234,9 @@
         if (mInlinePresentation != null) {
             builder.append(", hasInlinePresentation");
         }
+        if (mInlineTooltipPresentation != null) {
+            builder.append(", hasInlineTooltipPresentation");
+        }
         if (mAuthentication != null) {
             builder.append(", hasAuthentication");
         }
@@ -245,10 +264,12 @@
         private ArrayList<AutofillValue> mFieldValues;
         private ArrayList<RemoteViews> mFieldPresentations;
         private ArrayList<InlinePresentation> mFieldInlinePresentations;
+        private ArrayList<InlinePresentation> mFieldInlineTooltipPresentations;
         private ArrayList<DatasetFieldFilter> mFieldFilters;
         @Nullable private ClipData mFieldContent;
         private RemoteViews mPresentation;
         @Nullable private InlinePresentation mInlinePresentation;
+        @Nullable private InlinePresentation mInlineTooltipPresentation;
         private IntentSender mAuthentication;
         private boolean mDestroyed;
         @Nullable private String mId;
@@ -306,6 +327,31 @@
         }
 
         /**
+         * Visualizes this dataset as inline suggestions.
+         *
+         * @param inlinePresentation the {@link InlinePresentation} used to visualize this
+         *         dataset as inline suggestions. If the dataset supports inline suggestions this
+         *         should not be null.
+         * @param inlineTooltipPresentation the {@link InlinePresentation} used to show
+         *         the tooltip for the {@code inlinePresentation}.
+         *
+         * @throws IllegalStateException if {@link #build()} was already called.
+         *
+         * @return this builder.
+         */
+        public @NonNull Builder setInlinePresentation(
+                @NonNull InlinePresentation inlinePresentation,
+                @NonNull InlinePresentation inlineTooltipPresentation) {
+            throwIfDestroyed();
+            Preconditions.checkNotNull(inlinePresentation, "inlinePresentation must be non-null");
+            Preconditions.checkNotNull(inlineTooltipPresentation,
+                    "inlineTooltipPresentation must be non-null");
+            mInlinePresentation = inlinePresentation;
+            mInlineTooltipPresentation = inlineTooltipPresentation;
+            return this;
+        }
+
+        /**
          * Triggers a custom UI before before autofilling the screen with the contents of this
          * dataset.
          *
@@ -598,6 +644,41 @@
 
         /**
          * Sets the value of a field, using a custom {@link RemoteViews presentation} to
+         * visualize it and an {@link InlinePresentation} to visualize it as an inline suggestion.
+         *
+         * @see #setValue(AutofillId, AutofillValue, RemoteViews, InlinePresentation)
+         *
+         * @param id id returned by {@link
+         *        android.app.assist.AssistStructure.ViewNode#getAutofillId()}.
+         * @param value the value to be autofilled. Pass {@code null} if you do not have the value
+         *        but the target view is a logical part of the dataset. For example, if
+         *        the dataset needs authentication and you have no access to the value.
+         * @param presentation the presentation used to visualize this field.
+         * @param inlinePresentation The {@link InlinePresentation} used to visualize this dataset
+         *        as inline suggestions. If the dataset supports inline suggestions,
+         *        this should not be null.
+         * @param inlineTooltipPresentation The {@link InlinePresentation} used to show
+         *        the tooltip for the {@code inlinePresentation}.
+         *
+         * @throws IllegalStateException if {@link #build()} was already called.
+         *
+         * @return this builder.
+         */
+        public @NonNull Builder setValue(@NonNull AutofillId id, @Nullable AutofillValue value,
+                @NonNull RemoteViews presentation, @NonNull InlinePresentation inlinePresentation,
+                @NonNull InlinePresentation inlineTooltipPresentation) {
+            throwIfDestroyed();
+            Preconditions.checkNotNull(presentation, "presentation cannot be null");
+            Preconditions.checkNotNull(inlinePresentation, "inlinePresentation cannot be null");
+            Preconditions.checkNotNull(inlineTooltipPresentation,
+                    "inlineTooltipPresentation cannot be null");
+            setLifeTheUniverseAndEverything(id, value, presentation, inlinePresentation,
+                    inlineTooltipPresentation, null);
+            return this;
+        }
+
+        /**
+         * Sets the value of a field, using a custom {@link RemoteViews presentation} to
          * visualize it and a <a href="#Filtering">explicit filter</a>, and an
          * {@link InlinePresentation} to visualize it as an inline suggestion.
          *
@@ -641,6 +722,47 @@
         }
 
         /**
+         * Sets the value of a field, using a custom {@link RemoteViews presentation} to
+         * visualize it and a <a href="#Filtering">explicit filter</a>, and an
+         * {@link InlinePresentation} to visualize it as an inline suggestion.
+         *
+         * @see #setValue(AutofillId, AutofillValue, Pattern, RemoteViews, InlinePresentation)
+         *
+         * @param id id returned by {@link
+         *         android.app.assist.AssistStructure.ViewNode#getAutofillId()}.
+         * @param value the value to be autofilled. Pass {@code null} if you do not have the value
+         *        but the target view is a logical part of the dataset. For example, if
+         *        the dataset needs authentication and you have no access to the value.
+         * @param filter regex used to determine if the dataset should be shown in the autofill UI;
+         *        when {@code null}, it disables filtering on that dataset (this is the recommended
+         *        approach when {@code value} is not {@code null} and field contains sensitive data
+         *        such as passwords).
+         * @param presentation the presentation used to visualize this field.
+         * @param inlinePresentation The {@link InlinePresentation} used to visualize this dataset
+         *        as inline suggestions. If the dataset supports inline suggestions, this
+         *        should not be null.
+         * @param inlineTooltipPresentation The {@link InlinePresentation} used to show
+         *        the tooltip for the {@code inlinePresentation}.
+         *
+         * @throws IllegalStateException if {@link #build()} was already called.
+         *
+         * @return this builder.
+         */
+        public @NonNull Builder setValue(@NonNull AutofillId id, @Nullable AutofillValue value,
+                @Nullable Pattern filter, @NonNull RemoteViews presentation,
+                @NonNull InlinePresentation inlinePresentation,
+                @NonNull InlinePresentation inlineTooltipPresentation) {
+            throwIfDestroyed();
+            Preconditions.checkNotNull(presentation, "presentation cannot be null");
+            Preconditions.checkNotNull(inlinePresentation, "inlinePresentation cannot be null");
+            Preconditions.checkNotNull(inlineTooltipPresentation,
+                    "inlineTooltipPresentation cannot be null");
+            setLifeTheUniverseAndEverything(id, value, presentation, inlinePresentation,
+                    inlineTooltipPresentation, new DatasetFieldFilter(filter));
+            return this;
+        }
+
+        /**
          * Sets the value of a field with an <a href="#Filtering">explicit filter</a>, and using an
          * {@link InlinePresentation} to visualize it as an inline suggestion.
          *
@@ -680,6 +802,15 @@
                 @Nullable AutofillValue value, @Nullable RemoteViews presentation,
                 @Nullable InlinePresentation inlinePresentation,
                 @Nullable DatasetFieldFilter filter) {
+            setLifeTheUniverseAndEverything(id, value, presentation, inlinePresentation, null,
+                    filter);
+        }
+
+        private void setLifeTheUniverseAndEverything(@NonNull AutofillId id,
+                @Nullable AutofillValue value, @Nullable RemoteViews presentation,
+                @Nullable InlinePresentation inlinePresentation,
+                @Nullable InlinePresentation tooltip,
+                @Nullable DatasetFieldFilter filter) {
             Preconditions.checkNotNull(id, "id cannot be null");
             if (mFieldIds != null) {
                 final int existingIdx = mFieldIds.indexOf(id);
@@ -687,6 +818,7 @@
                     mFieldValues.set(existingIdx, value);
                     mFieldPresentations.set(existingIdx, presentation);
                     mFieldInlinePresentations.set(existingIdx, inlinePresentation);
+                    mFieldInlineTooltipPresentations.set(existingIdx, tooltip);
                     mFieldFilters.set(existingIdx, filter);
                     return;
                 }
@@ -695,12 +827,14 @@
                 mFieldValues = new ArrayList<>();
                 mFieldPresentations = new ArrayList<>();
                 mFieldInlinePresentations = new ArrayList<>();
+                mFieldInlineTooltipPresentations = new ArrayList<>();
                 mFieldFilters = new ArrayList<>();
             }
             mFieldIds.add(id);
             mFieldValues.add(value);
             mFieldPresentations.add(presentation);
             mFieldInlinePresentations.add(inlinePresentation);
+            mFieldInlineTooltipPresentations.add(tooltip);
             mFieldFilters.add(filter);
         }
 
@@ -755,10 +889,12 @@
     public void writeToParcel(Parcel parcel, int flags) {
         parcel.writeParcelable(mPresentation, flags);
         parcel.writeParcelable(mInlinePresentation, flags);
+        parcel.writeParcelable(mInlineTooltipPresentation, flags);
         parcel.writeTypedList(mFieldIds, flags);
         parcel.writeTypedList(mFieldValues, flags);
         parcel.writeTypedList(mFieldPresentations, flags);
         parcel.writeTypedList(mFieldInlinePresentations, flags);
+        parcel.writeTypedList(mFieldInlineTooltipPresentations, flags);
         parcel.writeTypedList(mFieldFilters, flags);
         parcel.writeParcelable(mFieldContent, flags);
         parcel.writeParcelable(mAuthentication, flags);
@@ -770,6 +906,8 @@
         public Dataset createFromParcel(Parcel parcel) {
             final RemoteViews presentation = parcel.readParcelable(null);
             final InlinePresentation inlinePresentation = parcel.readParcelable(null);
+            final InlinePresentation inlineTooltipPresentation =
+                    parcel.readParcelable(null);
             final ArrayList<AutofillId> ids =
                     parcel.createTypedArrayList(AutofillId.CREATOR);
             final ArrayList<AutofillValue> values =
@@ -778,6 +916,8 @@
                     parcel.createTypedArrayList(RemoteViews.CREATOR);
             final ArrayList<InlinePresentation> inlinePresentations =
                     parcel.createTypedArrayList(InlinePresentation.CREATOR);
+            final ArrayList<InlinePresentation> inlineTooltipPresentations =
+                    parcel.createTypedArrayList(InlinePresentation.CREATOR);
             final ArrayList<DatasetFieldFilter> filters =
                     parcel.createTypedArrayList(DatasetFieldFilter.CREATOR);
             final ClipData fieldContent = parcel.readParcelable(null);
@@ -790,8 +930,13 @@
             final Builder builder = (presentation != null) ? new Builder(presentation)
                     : new Builder();
             if (inlinePresentation != null) {
-                builder.setInlinePresentation(inlinePresentation);
+                if (inlineTooltipPresentation != null) {
+                    builder.setInlinePresentation(inlinePresentation, inlineTooltipPresentation);
+                } else {
+                    builder.setInlinePresentation(inlinePresentation);
+                }
             }
+
             if (fieldContent != null) {
                 builder.setContent(ids.get(0), fieldContent);
             }
@@ -802,9 +947,11 @@
                 final RemoteViews fieldPresentation = presentations.get(i);
                 final InlinePresentation fieldInlinePresentation =
                         i < inlinePresentationsSize ? inlinePresentations.get(i) : null;
+                final InlinePresentation fieldInlineTooltipPresentation =
+                        i < inlinePresentationsSize ? inlineTooltipPresentations.get(i) : null;
                 final DatasetFieldFilter filter = filters.get(i);
                 builder.setLifeTheUniverseAndEverything(id, value, fieldPresentation,
-                        fieldInlinePresentation, filter);
+                        fieldInlinePresentation, fieldInlineTooltipPresentation, filter);
             }
             builder.setAuthentication(authentication);
             builder.setId(datasetId);
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index b1107a8..740ae26 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -23,6 +23,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.annotation.TestApi;
 import android.app.Activity;
 import android.content.IntentSender;
@@ -76,6 +77,7 @@
     private final @Nullable Bundle mClientState;
     private final @Nullable RemoteViews mPresentation;
     private final @Nullable InlinePresentation mInlinePresentation;
+    private final @Nullable InlinePresentation mInlineTooltipPresentation;
     private final @Nullable RemoteViews mHeader;
     private final @Nullable RemoteViews mFooter;
     private final @Nullable IntentSender mAuthentication;
@@ -95,6 +97,7 @@
         mClientState = builder.mClientState;
         mPresentation = builder.mPresentation;
         mInlinePresentation = builder.mInlinePresentation;
+        mInlineTooltipPresentation = builder.mInlineTooltipPresentation;
         mHeader = builder.mHeader;
         mFooter = builder.mFooter;
         mAuthentication = builder.mAuthentication;
@@ -135,6 +138,11 @@
     }
 
     /** @hide */
+    public @Nullable InlinePresentation getInlineTooltipPresentation() {
+        return mInlineTooltipPresentation;
+    }
+
+    /** @hide */
     public @Nullable RemoteViews getHeader() {
         return mHeader;
     }
@@ -219,6 +227,7 @@
         private Bundle mClientState;
         private RemoteViews mPresentation;
         private InlinePresentation mInlinePresentation;
+        private InlinePresentation mInlineTooltipPresentation;
         private RemoteViews mHeader;
         private RemoteViews mFooter;
         private IntentSender mAuthentication;
@@ -360,6 +369,22 @@
         public Builder setAuthentication(@NonNull AutofillId[] ids,
                 @Nullable IntentSender authentication, @Nullable RemoteViews presentation,
                 @Nullable InlinePresentation inlinePresentation) {
+            return setAuthentication(ids, authentication, presentation, inlinePresentation, null);
+        }
+
+        /**
+         * Triggers a custom UI before before autofilling the screen with any data set in this
+         * response.
+         *
+         * <p>This method like
+         * {@link #setAuthentication(AutofillId[], IntentSender, RemoteViews, InlinePresentation)}
+         * but allows setting an {@link InlinePresentation} for the inline suggestion tooltip.
+         */
+        @NonNull
+        public Builder setAuthentication(@SuppressLint("ArrayReturn") @NonNull AutofillId[] ids,
+                @Nullable IntentSender authentication, @Nullable RemoteViews presentation,
+                @Nullable InlinePresentation inlinePresentation,
+                @Nullable InlinePresentation inlineTooltipPresentation) {
             throwIfDestroyed();
             throwIfDisableAutofillCalled();
             if (mHeader != null || mFooter != null) {
@@ -373,6 +398,7 @@
             mAuthentication = authentication;
             mPresentation = presentation;
             mInlinePresentation = inlinePresentation;
+            mInlineTooltipPresentation = inlineTooltipPresentation;
             mAuthenticationIds = assertValid(ids);
             return this;
         }
@@ -737,6 +763,9 @@
         if (mInlinePresentation != null) {
             builder.append(", hasInlinePresentation");
         }
+        if (mInlineTooltipPresentation != null) {
+            builder.append(", hasInlineTooltipPresentation");
+        }
         if (mHeader != null) {
             builder.append(", hasHeader");
         }
@@ -784,6 +813,7 @@
         parcel.writeParcelable(mAuthentication, flags);
         parcel.writeParcelable(mPresentation, flags);
         parcel.writeParcelable(mInlinePresentation, flags);
+        parcel.writeParcelable(mInlineTooltipPresentation, flags);
         parcel.writeParcelable(mHeader, flags);
         parcel.writeParcelable(mFooter, flags);
         parcel.writeParcelable(mUserData, flags);
@@ -818,9 +848,10 @@
             final IntentSender authentication = parcel.readParcelable(null);
             final RemoteViews presentation = parcel.readParcelable(null);
             final InlinePresentation inlinePresentation = parcel.readParcelable(null);
+            final InlinePresentation inlineTooltipPresentation = parcel.readParcelable(null);
             if (authenticationIds != null) {
                 builder.setAuthentication(authenticationIds, authentication, presentation,
-                        inlinePresentation);
+                        inlinePresentation, inlineTooltipPresentation);
             }
             final RemoteViews header = parcel.readParcelable(null);
             if (header != null) {
diff --git a/core/java/android/service/autofill/InlinePresentation.java b/core/java/android/service/autofill/InlinePresentation.java
index fbf23b6..4034957 100644
--- a/core/java/android/service/autofill/InlinePresentation.java
+++ b/core/java/android/service/autofill/InlinePresentation.java
@@ -75,9 +75,23 @@
         return hints.toArray(new String[hints.size()]);
     }
 
+    /**
+     * Creates a presentation for the inline suggestion tooltip
+     *
+     * @param slice Represents the UI content and the action for the inline suggestion tooltip.
+     * @param spec Specifies the UI specification for the inline suggestion tooltip.
+     * @return An {@link InlinePresentation} for the inline suggestion tooltip
+     */
+    @NonNull
+    public static InlinePresentation createTooltipPresentation(@NonNull Slice slice,
+            @NonNull InlinePresentationSpec spec) {
+        return new InlinePresentation(slice, spec, /* pinned */ false);
+
+    }
 
 
-    // Code below generated by codegen v1.0.20.
+
+    // Code below generated by codegen v1.0.22.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -259,10 +273,10 @@
     };
 
     @DataClass.Generated(
-            time = 1604456277638L,
-            codegenVersion = "1.0.20",
+            time = 1615968415006L,
+            codegenVersion = "1.0.22",
             sourceFile = "frameworks/base/core/java/android/service/autofill/InlinePresentation.java",
-            inputSignatures = "private final @android.annotation.NonNull android.app.slice.Slice mSlice\nprivate final @android.annotation.NonNull android.widget.inline.InlinePresentationSpec mInlinePresentationSpec\nprivate final  boolean mPinned\npublic @android.annotation.NonNull @android.annotation.Size java.lang.String[] getAutofillHints()\nclass InlinePresentation extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstDefs=true, genEqualsHashCode=true)")
+            inputSignatures = "private final @android.annotation.NonNull android.app.slice.Slice mSlice\nprivate final @android.annotation.NonNull android.widget.inline.InlinePresentationSpec mInlinePresentationSpec\nprivate final  boolean mPinned\npublic @android.annotation.NonNull @android.annotation.Size java.lang.String[] getAutofillHints()\npublic static @android.annotation.NonNull android.service.autofill.InlinePresentation createTooltipPresentation(android.app.slice.Slice,android.widget.inline.InlinePresentationSpec)\nclass InlinePresentation extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstDefs=true, genEqualsHashCode=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 7aa5bbc9..bf5f24d 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -1786,7 +1786,8 @@
          * {@link NotificationListenerService.Ranking#VISIBILITY_NO_OVERRIDE} if
          * no such preference has been expressed.
          */
-        public int getLockscreenVisibilityOverride() {
+        public @Notification.NotificationVisibilityOverride
+        int getLockscreenVisibilityOverride() {
             return mVisibilityOverride;
         }
 
diff --git a/telephony/java/android/telephony/data/SliceInfo.aidl b/core/java/android/service/voice/HotwordDetectedResult.aidl
similarity index 81%
copy from telephony/java/android/telephony/data/SliceInfo.aidl
copy to core/java/android/service/voice/HotwordDetectedResult.aidl
index 286ea5e..c3201a19 100644
--- a/telephony/java/android/telephony/data/SliceInfo.aidl
+++ b/core/java/android/service/voice/HotwordDetectedResult.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-/** @hide */
-package android.telephony.data;
+package android.service.voice;
 
-parcelable SliceInfo;
+parcelable HotwordDetectedResult;
diff --git a/core/java/android/service/voice/HotwordDetectedResult.java b/core/java/android/service/voice/HotwordDetectedResult.java
new file mode 100644
index 0000000..dd6f698
--- /dev/null
+++ b/core/java/android/service/voice/HotwordDetectedResult.java
@@ -0,0 +1,501 @@
+/*
+ * 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.service.voice;
+
+import static android.service.voice.HotwordDetector.CONFIDENCE_LEVEL_NONE;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Bundle;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * Represents a result supporting the hotword detection.
+ *
+ * @hide
+ */
+@DataClass(
+        genConstructor = false,
+        genBuilder = true,
+        genEqualsHashCode = true,
+        genHiddenConstDefs = true,
+        genParcelable = true,
+        genToString = true
+)
+@SystemApi
+public final class HotwordDetectedResult implements Parcelable {
+
+    /** Represents unset value for byte offset. */
+    public static final int BYTE_OFFSET_UNSET = -1;
+
+    /** Confidence level in the trigger outcome. */
+    @HotwordDetector.HotwordConfidenceLevelValue
+    private final int mConfidenceLevel;
+    private static int defaultConfidenceLevel() {
+        return CONFIDENCE_LEVEL_NONE;
+    }
+
+    /**
+     * Byte offset in the audio stream when the trigger event happened.
+     *
+     * <p>If unset, the most recent bytes in the audio stream will be used.
+     */
+    private final int mByteOffset;
+    private static int defaultByteOffset() {
+        return BYTE_OFFSET_UNSET;
+    }
+
+    /**
+     * Score for the hotword trigger.
+     *
+     * <p>Only values between 0 and {@link #getMaxScore} (inclusive) are accepted.
+     */
+    private final int mScore;
+    private static int defaultScore() {
+        return 0;
+    }
+
+    /**
+     * Score for the hotword trigger for device user.
+     *
+     * <p>Only values between 0 and {@link #getMaxScore} (inclusive) are accepted.
+     */
+    private final int mPersonalizedScore;
+    private static int defaultPersonalizedScore() {
+        return 0;
+    }
+
+    /**
+     * Returns the maximum values of {@link #getScore} and {@link #getPersonalizedScore}.
+     *
+     * The float value should be calculated as {@code getScore() / getMaxScore()}.
+     */
+    public static int getMaxScore() {
+        return 255;
+    }
+
+    /**
+     * Triggered phrase.
+     *
+     * <p>This phrase has to be listed in the AndroidManifest of the application in order for
+     * trigger to be accepted by the system.
+     */
+    // TODO(b/183128696): allow listing this in the manifest.
+    @Nullable
+    private final String mHotwordPhrase;
+    private static String defaultHotwordPhrase() {
+        return null;
+    }
+
+    /**
+     * App-specific extras to support trigger.
+     *
+     * <p>The size of this bundle will be limited to {@link #getMaxBundleSize}. Results will larger
+     * bundles will be rejected.
+     *
+     * <p>Only primitive types are supported in this bundle. Complex types will be removed from the
+     * bundle.
+     *
+     * <p>The use of this method is discouraged, and support for it will be removed in future
+     * versions of Android.
+     */
+    @NonNull
+    private final Bundle mExtras;
+    private static Bundle defaultExtras() {
+        return new Bundle();
+    }
+
+    /**
+     * Returns the maximum byte size of the information contained in the bundle.
+     *
+     * <p>The total size will be calculated as a sum of byte sizes over all bundle keys.
+     *
+     * <p>For example, for a bundle containing a single key: {@code "example_key" -> 42.0f}, the
+     * bundle size will be {@code 11 + Float.BYTES = 15} bytes.
+     */
+    public static int getMaxBundleSize() {
+        return 50;
+    }
+
+
+
+    // 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/service/voice/HotwordDetectedResult.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 */ HotwordDetectedResult(
+            @HotwordDetector.HotwordConfidenceLevelValue int confidenceLevel,
+            int byteOffset,
+            int score,
+            int personalizedScore,
+            @Nullable String hotwordPhrase,
+            @NonNull Bundle extras) {
+        this.mConfidenceLevel = confidenceLevel;
+        com.android.internal.util.AnnotationValidations.validate(
+                HotwordDetector.HotwordConfidenceLevelValue.class, null, mConfidenceLevel);
+        this.mByteOffset = byteOffset;
+        this.mScore = score;
+        this.mPersonalizedScore = personalizedScore;
+        this.mHotwordPhrase = hotwordPhrase;
+        this.mExtras = extras;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mExtras);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    /**
+     * Confidence level in the trigger outcome.
+     */
+    @DataClass.Generated.Member
+    public @HotwordDetector.HotwordConfidenceLevelValue int getConfidenceLevel() {
+        return mConfidenceLevel;
+    }
+
+    /**
+     * Byte offset in the audio stream when the trigger event happened.
+     *
+     * <p>If unset, the most recent bytes in the audio stream will be used.
+     */
+    @DataClass.Generated.Member
+    public int getByteOffset() {
+        return mByteOffset;
+    }
+
+    /**
+     * Score for the hotword trigger.
+     *
+     * <p>Only values between 0 and {@link #getMaxScore} (inclusive) are accepted.
+     */
+    @DataClass.Generated.Member
+    public int getScore() {
+        return mScore;
+    }
+
+    /**
+     * Score for the hotword trigger for device user.
+     *
+     * <p>Only values between 0 and {@link #getMaxScore} (inclusive) are accepted.
+     */
+    @DataClass.Generated.Member
+    public int getPersonalizedScore() {
+        return mPersonalizedScore;
+    }
+
+    @DataClass.Generated.Member
+    public @Nullable String getHotwordPhrase() {
+        return mHotwordPhrase;
+    }
+
+    /**
+     * App-specific extras to support trigger.
+     *
+     * <p>The size of this bundle will be limited to {@link #getMaxBundleSize}. Results will larger
+     * bundles will be rejected.
+     *
+     * <p>Only primitive types are supported in this bundle. Complex types will be removed from the
+     * bundle.
+     *
+     * <p>The use of this method is discouraged, and support for it will be removed in future
+     * versions of Android.
+     */
+    @DataClass.Generated.Member
+    public @NonNull Bundle getExtras() {
+        return mExtras;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "HotwordDetectedResult { " +
+                "confidenceLevel = " + mConfidenceLevel + ", " +
+                "byteOffset = " + mByteOffset + ", " +
+                "score = " + mScore + ", " +
+                "personalizedScore = " + mPersonalizedScore + ", " +
+                "hotwordPhrase = " + mHotwordPhrase + ", " +
+                "extras = " + mExtras +
+        " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public boolean equals(@Nullable Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(HotwordDetectedResult other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        HotwordDetectedResult that = (HotwordDetectedResult) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && mConfidenceLevel == that.mConfidenceLevel
+                && mByteOffset == that.mByteOffset
+                && mScore == that.mScore
+                && mPersonalizedScore == that.mPersonalizedScore
+                && java.util.Objects.equals(mHotwordPhrase, that.mHotwordPhrase)
+                && java.util.Objects.equals(mExtras, that.mExtras);
+    }
+
+    @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 + mConfidenceLevel;
+        _hash = 31 * _hash + mByteOffset;
+        _hash = 31 * _hash + mScore;
+        _hash = 31 * _hash + mPersonalizedScore;
+        _hash = 31 * _hash + java.util.Objects.hashCode(mHotwordPhrase);
+        _hash = 31 * _hash + java.util.Objects.hashCode(mExtras);
+        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 (mHotwordPhrase != null) flg |= 0x10;
+        dest.writeByte(flg);
+        dest.writeInt(mConfidenceLevel);
+        dest.writeInt(mByteOffset);
+        dest.writeInt(mScore);
+        dest.writeInt(mPersonalizedScore);
+        if (mHotwordPhrase != null) dest.writeString(mHotwordPhrase);
+        dest.writeBundle(mExtras);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ HotwordDetectedResult(@NonNull android.os.Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        byte flg = in.readByte();
+        int confidenceLevel = in.readInt();
+        int byteOffset = in.readInt();
+        int score = in.readInt();
+        int personalizedScore = in.readInt();
+        String hotwordPhrase = (flg & 0x10) == 0 ? null : in.readString();
+        Bundle extras = in.readBundle();
+
+        this.mConfidenceLevel = confidenceLevel;
+        com.android.internal.util.AnnotationValidations.validate(
+                HotwordDetector.HotwordConfidenceLevelValue.class, null, mConfidenceLevel);
+        this.mByteOffset = byteOffset;
+        this.mScore = score;
+        this.mPersonalizedScore = personalizedScore;
+        this.mHotwordPhrase = hotwordPhrase;
+        this.mExtras = extras;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mExtras);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<HotwordDetectedResult> CREATOR
+            = new Parcelable.Creator<HotwordDetectedResult>() {
+        @Override
+        public HotwordDetectedResult[] newArray(int size) {
+            return new HotwordDetectedResult[size];
+        }
+
+        @Override
+        public HotwordDetectedResult createFromParcel(@NonNull android.os.Parcel in) {
+            return new HotwordDetectedResult(in);
+        }
+    };
+
+    /**
+     * A builder for {@link HotwordDetectedResult}
+     */
+    @SuppressWarnings("WeakerAccess")
+    @DataClass.Generated.Member
+    public static final class Builder {
+
+        private @HotwordDetector.HotwordConfidenceLevelValue int mConfidenceLevel;
+        private int mByteOffset;
+        private int mScore;
+        private int mPersonalizedScore;
+        private @Nullable String mHotwordPhrase;
+        private @NonNull Bundle mExtras;
+
+        private long mBuilderFieldsSet = 0L;
+
+        public Builder() {
+        }
+
+        /**
+         * Confidence level in the trigger outcome.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setConfidenceLevel(@HotwordDetector.HotwordConfidenceLevelValue int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x1;
+            mConfidenceLevel = value;
+            return this;
+        }
+
+        /**
+         * Byte offset in the audio stream when the trigger event happened.
+         *
+         * <p>If unset, the most recent bytes in the audio stream will be used.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setByteOffset(int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x2;
+            mByteOffset = value;
+            return this;
+        }
+
+        /**
+         * Score for the hotword trigger.
+         *
+         * <p>Only values between 0 and {@link #getMaxScore} (inclusive) are accepted.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setScore(int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x4;
+            mScore = value;
+            return this;
+        }
+
+        /**
+         * Score for the hotword trigger for device user.
+         *
+         * <p>Only values between 0 and {@link #getMaxScore} (inclusive) are accepted.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setPersonalizedScore(int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x8;
+            mPersonalizedScore = value;
+            return this;
+        }
+
+        @DataClass.Generated.Member
+        public @NonNull Builder setHotwordPhrase(@NonNull String value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x10;
+            mHotwordPhrase = value;
+            return this;
+        }
+
+        /**
+         * App-specific extras to support trigger.
+         *
+         * <p>The size of this bundle will be limited to {@link #getMaxBundleSize}. Results will larger
+         * bundles will be rejected.
+         *
+         * <p>Only primitive types are supported in this bundle. Complex types will be removed from the
+         * bundle.
+         *
+         * <p>The use of this method is discouraged, and support for it will be removed in future
+         * versions of Android.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setExtras(@NonNull Bundle value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x20;
+            mExtras = value;
+            return this;
+        }
+
+        /** Builds the instance. This builder should not be touched after calling this! */
+        public @NonNull HotwordDetectedResult build() {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x40; // Mark builder used
+
+            if ((mBuilderFieldsSet & 0x1) == 0) {
+                mConfidenceLevel = defaultConfidenceLevel();
+            }
+            if ((mBuilderFieldsSet & 0x2) == 0) {
+                mByteOffset = defaultByteOffset();
+            }
+            if ((mBuilderFieldsSet & 0x4) == 0) {
+                mScore = defaultScore();
+            }
+            if ((mBuilderFieldsSet & 0x8) == 0) {
+                mPersonalizedScore = defaultPersonalizedScore();
+            }
+            if ((mBuilderFieldsSet & 0x10) == 0) {
+                mHotwordPhrase = defaultHotwordPhrase();
+            }
+            if ((mBuilderFieldsSet & 0x20) == 0) {
+                mExtras = defaultExtras();
+            }
+            HotwordDetectedResult o = new HotwordDetectedResult(
+                    mConfidenceLevel,
+                    mByteOffset,
+                    mScore,
+                    mPersonalizedScore,
+                    mHotwordPhrase,
+                    mExtras);
+            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 = 1616110545582L,
+            codegenVersion = "1.0.22",
+            sourceFile = "frameworks/base/core/java/android/service/voice/HotwordDetectedResult.java",
+            inputSignatures = "public static final  int BYTE_OFFSET_UNSET\nprivate final @android.service.voice.HotwordDetector.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate final  int mByteOffset\nprivate final  int mScore\nprivate final  int mPersonalizedScore\nprivate final @android.annotation.Nullable java.lang.String mHotwordPhrase\nprivate final @android.annotation.NonNull android.os.Bundle mExtras\nprivate static  int defaultConfidenceLevel()\nprivate static  int defaultByteOffset()\nprivate static  int defaultScore()\nprivate static  int defaultPersonalizedScore()\npublic static  int getMaxScore()\nprivate static  java.lang.String defaultHotwordPhrase()\nprivate static  android.os.Bundle defaultExtras()\npublic static  int getMaxBundleSize()\nclass HotwordDetectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/service/voice/HotwordDetector.java b/core/java/android/service/voice/HotwordDetector.java
new file mode 100644
index 0000000..abf49b7
--- /dev/null
+++ b/core/java/android/service/voice/HotwordDetector.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 android.service.voice;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+
+/**
+ * Basic functionality for hotword detectors.
+ *
+ * @hide
+ */
+@SystemApi
+public interface HotwordDetector {
+
+    /** No confidence in hotword detector result. */
+    int CONFIDENCE_LEVEL_NONE = 0;
+
+    /** Small confidence in hotword detector result. */
+    int CONFIDENCE_LEVEL_LOW = 1;
+
+    /** Medium confidence in hotword detector result. */
+    int CONFIDENCE_LEVEL_MEDIUM = 2;
+
+    /** High confidence in hotword detector result. */
+    int CONFIDENCE_LEVEL_HIGH = 3;
+
+    /** @hide */
+    @IntDef(prefix = { "CONFIDENCE_LEVEL_" }, value = {
+            CONFIDENCE_LEVEL_NONE,
+            CONFIDENCE_LEVEL_LOW,
+            CONFIDENCE_LEVEL_MEDIUM,
+            CONFIDENCE_LEVEL_HIGH
+    })
+    @interface HotwordConfidenceLevelValue {}
+}
diff --git a/telephony/java/android/telephony/data/SliceInfo.aidl b/core/java/android/service/voice/HotwordRejectedResult.aidl
similarity index 81%
copy from telephony/java/android/telephony/data/SliceInfo.aidl
copy to core/java/android/service/voice/HotwordRejectedResult.aidl
index 286ea5e..ef38a15 100644
--- a/telephony/java/android/telephony/data/SliceInfo.aidl
+++ b/core/java/android/service/voice/HotwordRejectedResult.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-/** @hide */
-package android.telephony.data;
+package android.service.voice;
 
-parcelable SliceInfo;
+parcelable HotwordRejectedResult;
diff --git a/core/java/android/service/voice/HotwordRejectedResult.java b/core/java/android/service/voice/HotwordRejectedResult.java
new file mode 100644
index 0000000..5d85662
--- /dev/null
+++ b/core/java/android/service/voice/HotwordRejectedResult.java
@@ -0,0 +1,222 @@
+/*
+ * 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.service.voice;
+
+import static android.service.voice.HotwordDetector.CONFIDENCE_LEVEL_NONE;
+
+import android.annotation.SystemApi;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * Represents a result supporting the rejected hotword trigger.
+ *
+ * @hide
+ */
+@DataClass(
+        genConstructor = false,
+        genHiddenBuilder = true,
+        genEqualsHashCode = true,
+        genHiddenConstDefs = true,
+        genParcelable = true,
+        genToString = true
+)
+@SystemApi
+public final class HotwordRejectedResult implements Parcelable {
+
+    /** Confidence level in the trigger outcome. */
+    @HotwordDetector.HotwordConfidenceLevelValue
+    private final int mConfidenceLevel;
+    private static int defaultConfidenceLevel() {
+        return CONFIDENCE_LEVEL_NONE;
+    }
+
+
+
+    // 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/service/voice/HotwordRejectedResult.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 */ HotwordRejectedResult(
+            @HotwordDetector.HotwordConfidenceLevelValue int confidenceLevel) {
+        this.mConfidenceLevel = confidenceLevel;
+        com.android.internal.util.AnnotationValidations.validate(
+                HotwordDetector.HotwordConfidenceLevelValue.class, null, mConfidenceLevel);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    /**
+     * Confidence level in the trigger outcome.
+     */
+    @DataClass.Generated.Member
+    public @HotwordDetector.HotwordConfidenceLevelValue int getConfidenceLevel() {
+        return mConfidenceLevel;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "HotwordRejectedResult { " +
+                "confidenceLevel = " + mConfidenceLevel +
+        " }";
+    }
+
+    @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(HotwordRejectedResult other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        HotwordRejectedResult that = (HotwordRejectedResult) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && mConfidenceLevel == that.mConfidenceLevel;
+    }
+
+    @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 + mConfidenceLevel;
+        return _hash;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@android.annotation.NonNull android.os.Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeInt(mConfidenceLevel);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ HotwordRejectedResult(@android.annotation.NonNull android.os.Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        int confidenceLevel = in.readInt();
+
+        this.mConfidenceLevel = confidenceLevel;
+        com.android.internal.util.AnnotationValidations.validate(
+                HotwordDetector.HotwordConfidenceLevelValue.class, null, mConfidenceLevel);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @android.annotation.NonNull Parcelable.Creator<HotwordRejectedResult> CREATOR
+            = new Parcelable.Creator<HotwordRejectedResult>() {
+        @Override
+        public HotwordRejectedResult[] newArray(int size) {
+            return new HotwordRejectedResult[size];
+        }
+
+        @Override
+        public HotwordRejectedResult createFromParcel(@android.annotation.NonNull android.os.Parcel in) {
+            return new HotwordRejectedResult(in);
+        }
+    };
+
+    /**
+     * A builder for {@link HotwordRejectedResult}
+     * @hide
+     */
+    @SuppressWarnings("WeakerAccess")
+    @DataClass.Generated.Member
+    public static final class Builder {
+
+        private @HotwordDetector.HotwordConfidenceLevelValue int mConfidenceLevel;
+
+        private long mBuilderFieldsSet = 0L;
+
+        public Builder() {
+        }
+
+        /**
+         * Confidence level in the trigger outcome.
+         */
+        @DataClass.Generated.Member
+        public @android.annotation.NonNull Builder setConfidenceLevel(@HotwordDetector.HotwordConfidenceLevelValue int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x1;
+            mConfidenceLevel = value;
+            return this;
+        }
+
+        /** Builds the instance. This builder should not be touched after calling this! */
+        public @android.annotation.NonNull HotwordRejectedResult build() {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x2; // Mark builder used
+
+            if ((mBuilderFieldsSet & 0x1) == 0) {
+                mConfidenceLevel = defaultConfidenceLevel();
+            }
+            HotwordRejectedResult o = new HotwordRejectedResult(
+                    mConfidenceLevel);
+            return o;
+        }
+
+        private void checkNotUsed() {
+            if ((mBuilderFieldsSet & 0x2) != 0) {
+                throw new IllegalStateException(
+                        "This Builder should not be reused. Use a new Builder instance instead");
+            }
+        }
+    }
+
+    @DataClass.Generated(
+            time = 1616108967315L,
+            codegenVersion = "1.0.22",
+            sourceFile = "frameworks/base/core/java/android/service/voice/HotwordRejectedResult.java",
+            inputSignatures = "private final @android.service.voice.HotwordDetector.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate static  int defaultConfidenceLevel()\nclass HotwordRejectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genHiddenBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index 048d9f5..9ba39a1 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -353,6 +353,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(Manifest.permission.MANAGE_HOTWORD_DETECTION)
     @NonNull
     public final AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(
             @SuppressLint("MissingNullability") String keyphrase,  // TODO: nullability properly
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index c1b66c7..ad09a48 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -1645,7 +1645,7 @@
 
     /**
      * Called to receive data from the application that the user was currently viewing when
-     * an assist session is started.  If the original show request did not specify
+-     * an assist session is started.  If the original show request did not specify
      * {@link #SHOW_WITH_ASSIST}, this method will not be called.
      *
      * @param data Arbitrary data supplied by the app through
@@ -1670,8 +1670,9 @@
 
     /**
      * Called to receive data from the application that the user was currently viewing when
-     * an assist session is started.  If the original show request did not specify
-     * {@link #SHOW_WITH_ASSIST}, this method will not be called.
+     * an assist session is started. If the original show request did not specify
+     * {@link #SHOW_WITH_ASSIST}, {@link AssistState} parameter will only provide
+     * {@link ActivityId}.
      *
      * <p>This method is called for all activities along with an index and count that indicates
      * which activity the data is for. {@code index} will be between 0 and {@code count}-1 and
@@ -1685,7 +1686,10 @@
      * @param state The state object capturing the state of an activity.
      */
     public void onHandleAssist(@NonNull AssistState state) {
-        if (state.getIndex() == 0) {
+        if (state.getAssistData() == null && state.getAssistStructure() == null
+                && state.getAssistContent() == null) {
+            return;
+        } else if (state.getIndex() == 0) {
             onHandleAssist(state.getAssistData(), state.getAssistStructure(),
                     state.getAssistContent());
         } else {
@@ -2028,7 +2032,8 @@
         /**
          * @return Arbitrary data supplied by the app through
          * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}.
-         * May be null if assist data has been disabled by the user or device policy.
+         * May be null if assist data has been disabled by the user or device policy; will be null
+         * if the original show request did not specify {@link #SHOW_WITH_ASSIST}.
          */
         public @Nullable Bundle getAssistData() {
             return mData;
@@ -2037,7 +2042,8 @@
         /**
          * @return If available, the structure definition of all windows currently
          * displayed by the app. May be null if assist data has been disabled by the user
-         * or device policy; will be an empty stub if the application has disabled assist
+         * or device policy; will be null if the original show request did not specify
+         * {@link #SHOW_WITH_ASSIST}; will be an empty stub if the application has disabled assist
          * by marking its window as secure.
          */
         public @Nullable AssistStructure getAssistStructure() {
@@ -2047,9 +2053,10 @@
         /**
          * @return Additional content data supplied by the app through
          * {@link android.app.Activity#onProvideAssistContent Activity.onProvideAssistContent}.
-         * May be null if assist data has been disabled by the user or device policy; will
-         * not be automatically filled in with data from the app if the app has marked its
-         * window as secure.
+         * May be null if assist data has been disabled by the user or device policy; will be null
+         * if the original show request did not specify {@link #SHOW_WITH_ASSIST}. Will not be
+         * automatically filled in with data from the app if the app has marked its window as
+         * secure.
          */
         public @Nullable AssistContent getAssistContent() {
             return mContent;
diff --git a/core/java/android/util/Slog.java b/core/java/android/util/Slog.java
index f61ab29..d3eaeae 100644
--- a/core/java/android/util/Slog.java
+++ b/core/java/android/util/Slog.java
@@ -30,11 +30,11 @@
  */
 public final class Slog {
 
-    @GuardedBy("sMessageBuilder")
-    private static final StringBuilder sMessageBuilder = new StringBuilder();
+    @GuardedBy("Slog.class")
+    private static StringBuilder sMessageBuilder;
 
-    @GuardedBy("sMessageBuilder")
-    private static final Formatter sFormatter = new Formatter(sMessageBuilder, Locale.ENGLISH);
+    @GuardedBy("Slog.class")
+    private static Formatter sFormatter;
 
     private Slog() {
     }
@@ -226,7 +226,12 @@
     }
 
     private static String getMessage(String format, @Nullable Object... args) {
-        synchronized (sMessageBuilder) {
+        synchronized (Slog.class) {
+            if (sMessageBuilder == null) {
+                // Lazy load so they're not created if not used by the process
+                sMessageBuilder = new StringBuilder();
+                sFormatter = new Formatter(sMessageBuilder, Locale.ENGLISH);
+            }
             sFormatter.format(format, args);
             String message = sMessageBuilder.toString();
             sMessageBuilder.setLength(0);
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index a89c540..7a61df8 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -29,6 +29,7 @@
 import static android.view.InsetsController.AnimationType;
 import static android.view.InsetsController.DEBUG;
 import static android.view.InsetsState.ISIDE_BOTTOM;
+import static android.view.InsetsState.ISIDE_FLOATING;
 import static android.view.InsetsState.ISIDE_LEFT;
 import static android.view.InsetsState.ISIDE_RIGHT;
 import static android.view.InsetsState.ISIDE_TOP;
@@ -74,8 +75,7 @@
 
     private final WindowInsetsAnimationControlListener mListener;
     private final SparseArray<InsetsSourceControl> mControls;
-    private final SparseIntArray mTypeSideMap = new SparseIntArray();
-    private final SparseSetArray<InsetsSourceControl> mSideSourceMap = new SparseSetArray<>();
+    private final SparseSetArray<InsetsSourceControl> mSideControlsMap = new SparseSetArray<>();
 
     /** @see WindowInsetsAnimationController#getHiddenStateInsets */
     private final Insets mHiddenInsets;
@@ -104,8 +104,8 @@
     private Boolean mPerceptible;
 
     @VisibleForTesting
-    public InsetsAnimationControlImpl(SparseArray<InsetsSourceControl> controls, Rect frame,
-            InsetsState state, WindowInsetsAnimationControlListener listener,
+    public InsetsAnimationControlImpl(SparseArray<InsetsSourceControl> controls,
+            @Nullable Rect frame, InsetsState state, WindowInsetsAnimationControlListener listener,
             @InsetsType int types,
             InsetsAnimationControlCallbacks controller, long durationMs, Interpolator interpolator,
             @AnimationType int animationType, CompatibilityInfo.Translator translator) {
@@ -114,19 +114,30 @@
         mTypes = types;
         mController = controller;
         mInitialInsetsState = new InsetsState(state, true /* copySources */);
-        mCurrentInsets = getInsetsFromState(mInitialInsetsState, frame, null /* typeSideMap */);
-        mPendingInsets = mCurrentInsets;
-        mHiddenInsets = calculateInsets(mInitialInsetsState, frame, controls, false /* shown */,
-                null /* typeSideMap */);
-        mShownInsets = calculateInsets(mInitialInsetsState, frame, controls, true /* shown */,
-                mTypeSideMap);
-        mHasZeroInsetsIme = mShownInsets.bottom == 0 && controlsInternalType(ITYPE_IME);
-        if (mHasZeroInsetsIme) {
-            // IME has shownInsets of ZERO, and can't map to a side by default.
-            // Map zero insets IME to bottom, making it a special case of bottom insets.
-            mTypeSideMap.put(ITYPE_IME, ISIDE_BOTTOM);
+        if (frame != null) {
+            final SparseIntArray typeSideMap = new SparseIntArray();
+            mCurrentInsets = getInsetsFromState(mInitialInsetsState, frame, null /* typeSideMap */);
+            mHiddenInsets = calculateInsets(mInitialInsetsState, frame, controls, false /* shown */,
+                    null /* typeSideMap */);
+            mShownInsets = calculateInsets(mInitialInsetsState, frame, controls, true /* shown */,
+                    typeSideMap);
+            mHasZeroInsetsIme = mShownInsets.bottom == 0 && controlsInternalType(ITYPE_IME);
+            if (mHasZeroInsetsIme) {
+                // IME has shownInsets of ZERO, and can't map to a side by default.
+                // Map zero insets IME to bottom, making it a special case of bottom insets.
+                typeSideMap.put(ITYPE_IME, ISIDE_BOTTOM);
+            }
+            buildSideControlsMap(typeSideMap, mSideControlsMap, controls);
+        } else {
+            // Passing a null frame indicates the caller wants to play the insets animation anyway,
+            // no matter the source provides insets to the frame or not.
+            mCurrentInsets = calculateInsets(mInitialInsetsState, controls, true /* shown */);
+            mHiddenInsets = calculateInsets(null, controls, false /* shown */);
+            mShownInsets = calculateInsets(null, controls, true /* shown */);
+            mHasZeroInsetsIme = mShownInsets.bottom == 0 && controlsInternalType(ITYPE_IME);
+            buildSideControlsMap(mSideControlsMap, controls);
         }
-        buildTypeSourcesMap(mTypeSideMap, mSideSourceMap, mControls);
+        mPendingInsets = mCurrentInsets;
 
         mAnimation = new WindowInsetsAnimation(mTypes, interpolator,
                 durationMs);
@@ -312,25 +323,10 @@
         proto.end(token);
     }
 
-    WindowInsetsAnimationControlListener getListener() {
-        return mListener;
-    }
-
     SparseArray<InsetsSourceControl> getControls() {
         return mControls;
     }
 
-    private Insets calculateInsets(InsetsState state, Rect frame,
-            SparseArray<InsetsSourceControl> controls, boolean shown,
-            @Nullable @InternalInsetsSide SparseIntArray typeSideMap) {
-        for (int i = controls.size() - 1; i >= 0; i--) {
-            // control may be null if it got revoked.
-            if (controls.valueAt(i) == null) continue;
-            state.getSource(controls.valueAt(i).getType()).setVisible(shown);
-        }
-        return getInsetsFromState(state, frame, typeSideMap);
-    }
-
     private Insets getInsetsFromState(InsetsState state, Rect frame,
             @Nullable @InternalInsetsSide SparseIntArray typeSideMap) {
         return state.calculateInsets(frame, null /* ignoringVisibilityState */,
@@ -340,6 +336,41 @@
                 WINDOWING_MODE_UNDEFINED, typeSideMap).getInsets(mTypes);
     }
 
+    /** Computes the insets relative to the given frame. */
+    private Insets calculateInsets(InsetsState state, Rect frame,
+            SparseArray<InsetsSourceControl> controls, boolean shown,
+            @Nullable @InternalInsetsSide SparseIntArray typeSideMap) {
+        for (int i = controls.size() - 1; i >= 0; i--) {
+            final InsetsSourceControl control  = controls.valueAt(i);
+            if (control == null) {
+                // control may be null if it got revoked.
+                continue;
+            }
+            state.getSource(control.getType()).setVisible(shown);
+        }
+        return getInsetsFromState(state, frame, typeSideMap);
+    }
+
+    /** Computes the insets from the insets hints of controls. */
+    private Insets calculateInsets(InsetsState state, SparseArray<InsetsSourceControl> controls,
+            boolean shownOrCurrent) {
+        Insets insets = Insets.NONE;
+        if (!shownOrCurrent) {
+            return insets;
+        }
+        for (int i = controls.size() - 1; i >= 0; i--) {
+            final InsetsSourceControl control  = controls.valueAt(i);
+            if (control == null) {
+                // control may be null if it got revoked.
+                continue;
+            }
+            if (state == null || state.getSource(control.getType()).isVisible()) {
+                insets = Insets.max(insets, control.getInsetsHint());
+            }
+        }
+        return insets;
+    }
+
     private Insets sanitize(Insets insets) {
         if (insets == null) {
             insets = getCurrentInsets();
@@ -356,13 +387,13 @@
 
     private void updateLeashesForSide(@InternalInsetsSide int side, int offset, int inset,
             ArrayList<SurfaceParams> surfaceParams, @Nullable InsetsState outState, float alpha) {
-        ArraySet<InsetsSourceControl> items = mSideSourceMap.get(side);
-        if (items == null) {
+        final ArraySet<InsetsSourceControl> controls = mSideControlsMap.get(side);
+        if (controls == null) {
             return;
         }
         // TODO: Implement behavior when inset spans over multiple types
-        for (int i = items.size() - 1; i >= 0; i--) {
-            final InsetsSourceControl control = items.valueAt(i);
+        for (int i = controls.size() - 1; i >= 0; i--) {
+            final InsetsSourceControl control = controls.valueAt(i);
             final InsetsSource source = mInitialInsetsState.getSource(control.getType());
             final SurfaceControl leash = control.getLeash();
 
@@ -371,7 +402,7 @@
             addTranslationToMatrix(side, offset, mTmpMatrix, mTmpFrame);
 
             final boolean visible = mHasZeroInsetsIme && side == ISIDE_BOTTOM
-                    ? (mAnimationType == ANIMATION_TYPE_SHOW ? true : !mFinished)
+                    ? (mAnimationType == ANIMATION_TYPE_SHOW || !mFinished)
                     : inset != 0;
 
             if (outState != null) {
@@ -391,32 +422,32 @@
         }
     }
 
-    private void addTranslationToMatrix(@InternalInsetsSide int side, int inset, Matrix m,
+    private void addTranslationToMatrix(@InternalInsetsSide int side, int offset, Matrix m,
             Rect frame) {
         final float surfaceOffset = mTranslator != null
-                ? mTranslator.translateLengthInAppWindowToScreen(inset) : inset;
+                ? mTranslator.translateLengthInAppWindowToScreen(offset) : offset;
         switch (side) {
             case ISIDE_LEFT:
                 m.postTranslate(-surfaceOffset, 0);
-                frame.offset(-inset, 0);
+                frame.offset(-offset, 0);
                 break;
             case ISIDE_TOP:
                 m.postTranslate(0, -surfaceOffset);
-                frame.offset(0, -inset);
+                frame.offset(0, -offset);
                 break;
             case ISIDE_RIGHT:
                 m.postTranslate(surfaceOffset, 0);
-                frame.offset(inset, 0);
+                frame.offset(offset, 0);
                 break;
             case ISIDE_BOTTOM:
                 m.postTranslate(0, surfaceOffset);
-                frame.offset(0, inset);
+                frame.offset(0, offset);
                 break;
         }
     }
 
-    private static void buildTypeSourcesMap(SparseIntArray typeSideMap,
-            SparseSetArray<InsetsSourceControl> sideSourcesMap,
+    private static void buildSideControlsMap(SparseIntArray typeSideMap,
+            SparseSetArray<InsetsSourceControl> sideControlsMap,
             SparseArray<InsetsSourceControl> controls) {
         for (int i = typeSideMap.size() - 1; i >= 0; i--) {
             final int type = typeSideMap.keyAt(i);
@@ -427,7 +458,24 @@
                 // there can be some null controllers.
                 continue;
             }
-            sideSourcesMap.add(side, control);
+            sideControlsMap.add(side, control);
+        }
+    }
+
+    private static void buildSideControlsMap(
+            SparseSetArray<InsetsSourceControl> sideControlsMap,
+            SparseArray<InsetsSourceControl> controls) {
+        for (int i = controls.size() - 1; i >= 0; i--) {
+            final InsetsSourceControl control  = controls.valueAt(i);
+            if (control == null) {
+                // control may be null if it got revoked.
+                continue;
+            }
+            @InternalInsetsSide int side = InsetsState.getInsetSide(control.getInsetsHint());
+            if (side == ISIDE_FLOATING && control.getType() == ITYPE_IME) {
+                side = ISIDE_BOTTOM;
+            }
+            sideControlsMap.add(side, control);
         }
     }
 }
diff --git a/core/java/android/view/InsetsAnimationThreadControlRunner.java b/core/java/android/view/InsetsAnimationThreadControlRunner.java
index 6a34a15..6122c90 100644
--- a/core/java/android/view/InsetsAnimationThreadControlRunner.java
+++ b/core/java/android/view/InsetsAnimationThreadControlRunner.java
@@ -19,6 +19,7 @@
 import static android.view.InsetsController.DEBUG;
 import static android.view.SyncRtSurfaceTransactionApplier.applyParams;
 
+import android.annotation.Nullable;
 import android.annotation.UiThread;
 import android.content.res.CompatibilityInfo;
 import android.graphics.Rect;
@@ -100,8 +101,8 @@
     };
 
     @UiThread
-    public InsetsAnimationThreadControlRunner(SparseArray<InsetsSourceControl> controls, Rect frame,
-            InsetsState state, WindowInsetsAnimationControlListener listener,
+    public InsetsAnimationThreadControlRunner(SparseArray<InsetsSourceControl> controls,
+            @Nullable Rect frame, InsetsState state, WindowInsetsAnimationControlListener listener,
             @InsetsType int types,
             InsetsAnimationControlCallbacks controller, long durationMs, Interpolator interpolator,
             @AnimationType int animationType, CompatibilityInfo.Translator translator,
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index e681c0e..8bf78db3 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -837,9 +837,12 @@
             PendingControlRequest pendingRequest = mPendingImeControlRequest;
             mPendingImeControlRequest = null;
             mHandler.removeCallbacks(mPendingControlTimeout);
+
+            // We are about to playing the default animation. Passing a null frame indicates the
+            // controlled types should be animated regardless of the frame.
             controlAnimationUnchecked(
                     pendingRequest.types, pendingRequest.cancellationSignal,
-                    pendingRequest.listener, mFrame,
+                    pendingRequest.listener, null /* frame */,
                     true /* fromIme */, pendingRequest.durationMs, pendingRequest.interpolator,
                     pendingRequest.animationType,
                     pendingRequest.layoutInsetsDuringAnimation,
@@ -934,7 +937,7 @@
 
     private void controlAnimationUnchecked(@InsetsType int types,
             @Nullable CancellationSignal cancellationSignal,
-            WindowInsetsAnimationControlListener listener, Rect frame, boolean fromIme,
+            WindowInsetsAnimationControlListener listener, @Nullable Rect frame, boolean fromIme,
             long durationMs, Interpolator interpolator,
             @AnimationType int animationType,
             @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
@@ -1358,10 +1361,10 @@
                 show, hasAnimationCallbacks, types, skipAnim || mAnimationsDisabled,
                 mHost.dipToPx(InternalAnimationControlListener.FLOATING_IME_BOTTOM_INSET));
 
-        // Show/hide animations always need to be relative to the display frame, in order that shown
-        // and hidden state insets are correct.
+        // We are about to playing the default animation (show/hide). Passing a null frame indicates
+        // the controlled types should be animated regardless of the frame.
         controlAnimationUnchecked(
-                types, null /* cancellationSignal */, listener, mState.getDisplayFrame(), fromIme,
+                types, null /* cancellationSignal */, listener, null /* frame */, fromIme,
                 listener.getDurationMs(), listener.getInterpolator(),
                 show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE,
                 show ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN,
diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java
index 1d4b411..9256bef 100644
--- a/core/java/android/view/InsetsSourceControl.java
+++ b/core/java/android/view/InsetsSourceControl.java
@@ -23,6 +23,7 @@
 import static android.view.InsetsSourceControlProto.TYPE;
 
 import android.annotation.Nullable;
+import android.graphics.Insets;
 import android.graphics.Point;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -41,13 +42,19 @@
     private final @InternalInsetsType int mType;
     private final @Nullable SurfaceControl mLeash;
     private final Point mSurfacePosition;
+
+    // This is used while playing an insets animation regardless of the relative frame. This would
+    // be the insets received by the bounds of its source window.
+    private Insets mInsetsHint;
+
     private boolean mSkipAnimationOnce;
 
     public InsetsSourceControl(@InternalInsetsType int type, @Nullable SurfaceControl leash,
-            Point surfacePosition) {
+            Point surfacePosition, Insets insetsHint) {
         mType = type;
         mLeash = leash;
         mSurfacePosition = surfacePosition;
+        mInsetsHint = insetsHint;
     }
 
     public InsetsSourceControl(InsetsSourceControl other) {
@@ -58,9 +65,18 @@
             mLeash = null;
         }
         mSurfacePosition = new Point(other.mSurfacePosition);
+        mInsetsHint = other.mInsetsHint;
         mSkipAnimationOnce = other.getAndClearSkipAnimationOnce();
     }
 
+    public InsetsSourceControl(Parcel in) {
+        mType = in.readInt();
+        mLeash = in.readTypedObject(SurfaceControl.CREATOR);
+        mSurfacePosition = in.readTypedObject(Point.CREATOR);
+        mInsetsHint = in.readTypedObject(Insets.CREATOR);
+        mSkipAnimationOnce = in.readBoolean();
+    }
+
     public int getType() {
         return mType;
     }
@@ -75,13 +91,6 @@
         return mLeash;
     }
 
-    public InsetsSourceControl(Parcel in) {
-        mType = in.readInt();
-        mLeash = in.readTypedObject(SurfaceControl.CREATOR);
-        mSurfacePosition = in.readTypedObject(Point.CREATOR);
-        mSkipAnimationOnce = in.readBoolean();
-    }
-
     public boolean setSurfacePosition(int left, int top) {
         if (mSurfacePosition.equals(left, top)) {
             return false;
@@ -90,14 +99,26 @@
         return true;
     }
 
-    public void setSkipAnimationOnce(boolean skipAnimation) {
-        mSkipAnimationOnce = skipAnimation;
-    }
-
     public Point getSurfacePosition() {
         return mSurfacePosition;
     }
 
+    public void setInsetsHint(Insets insets) {
+        mInsetsHint = insets;
+    }
+
+    public void setInsetsHint(int left, int top, int right, int bottom) {
+        mInsetsHint = Insets.of(left, top, right, bottom);
+    }
+
+    public Insets getInsetsHint() {
+        return mInsetsHint;
+    }
+
+    public void setSkipAnimationOnce(boolean skipAnimation) {
+        mSkipAnimationOnce = skipAnimation;
+    }
+
     /**
      * Get the state whether the current control needs to skip animation or not.
      *
@@ -121,6 +142,7 @@
         dest.writeInt(mType);
         dest.writeTypedObject(mLeash, 0 /* parcelableFlags */);
         dest.writeTypedObject(mSurfacePosition, 0 /* parcelableFlags */);
+        dest.writeTypedObject(mInsetsHint, 0 /* parcelableFlags */);
         dest.writeBoolean(mSkipAnimationOnce);
     }
 
@@ -135,6 +157,7 @@
         pw.print("InsetsSourceControl type="); pw.print(InsetsState.typeToString(mType));
         pw.print(" mLeash="); pw.print(mLeash);
         pw.print(" mSurfacePosition="); pw.print(mSurfacePosition);
+        pw.print(" mInsetsHint="); pw.print(mInsetsHint);
         pw.print(" mSkipAnimationOnce="); pw.print(mSkipAnimationOnce);
         pw.println();
     }
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index fce1952..3d1c8ff 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -400,7 +400,7 @@
      * Retrieves the side for a certain {@code insets}. It is required that only one field l/t/r/b
      * is set in order that this method returns a meaningful result.
      */
-    private @InternalInsetsSide int getInsetSide(Insets insets) {
+    static @InternalInsetsSide int getInsetSide(Insets insets) {
         if (Insets.NONE.equals(insets)) {
             return ISIDE_FLOATING;
         }
diff --git a/core/java/android/view/RemoteAnimationTarget.java b/core/java/android/view/RemoteAnimationTarget.java
index b1b670f..14dcdad 100644
--- a/core/java/android/view/RemoteAnimationTarget.java
+++ b/core/java/android/view/RemoteAnimationTarget.java
@@ -31,6 +31,7 @@
 import static android.view.RemoteAnimationTargetProto.START_LEASH;
 import static android.view.RemoteAnimationTargetProto.TASK_ID;
 import static android.view.RemoteAnimationTargetProto.WINDOW_CONFIGURATION;
+import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
 
 import android.annotation.IntDef;
 import android.app.PictureInPictureParams;
@@ -195,12 +196,30 @@
      */
     public PictureInPictureParams pictureInPictureParams;
 
+    /**
+     * The {@link android.view.WindowManager.LayoutParams.WindowType} of this window. It's only used
+     * for non-app window.
+     */
+    public final @WindowManager.LayoutParams.WindowType int windowType;
+
     public RemoteAnimationTarget(int taskId, int mode, SurfaceControl leash, boolean isTranslucent,
             Rect clipRect, Rect contentInsets, int prefixOrderIndex, Point position,
             Rect localBounds, Rect screenSpaceBounds,
             WindowConfiguration windowConfig, boolean isNotInRecents,
             SurfaceControl startLeash, Rect startBounds,
             PictureInPictureParams pictureInPictureParams) {
+        this(taskId, mode, leash, isTranslucent, clipRect, contentInsets, prefixOrderIndex,
+                position, localBounds, screenSpaceBounds, windowConfig, isNotInRecents, startLeash,
+                startBounds, pictureInPictureParams, INVALID_WINDOW_TYPE);
+    }
+
+    public RemoteAnimationTarget(int taskId, int mode, SurfaceControl leash, boolean isTranslucent,
+            Rect clipRect, Rect contentInsets, int prefixOrderIndex, Point position,
+            Rect localBounds, Rect screenSpaceBounds,
+            WindowConfiguration windowConfig, boolean isNotInRecents,
+            SurfaceControl startLeash, Rect startBounds,
+            PictureInPictureParams pictureInPictureParams,
+            @WindowManager.LayoutParams.WindowType int windowType) {
         this.mode = mode;
         this.taskId = taskId;
         this.leash = leash;
@@ -217,6 +236,7 @@
         this.startLeash = startLeash;
         this.startBounds = startBounds == null ? null : new Rect(startBounds);
         this.pictureInPictureParams = pictureInPictureParams;
+        this.windowType = windowType;
     }
 
     public RemoteAnimationTarget(Parcel in) {
@@ -236,6 +256,7 @@
         startLeash = in.readTypedObject(SurfaceControl.CREATOR);
         startBounds = in.readTypedObject(Rect.CREATOR);
         pictureInPictureParams = in.readTypedObject(PictureInPictureParams.CREATOR);
+        windowType = in.readInt();
     }
 
     @Override
@@ -261,6 +282,7 @@
         dest.writeTypedObject(startLeash, 0 /* flags */);
         dest.writeTypedObject(startBounds, 0 /* flags */);
         dest.writeTypedObject(pictureInPictureParams, 0 /* flags */);
+        dest.writeInt(windowType);
     }
 
     public void dump(PrintWriter pw, String prefix) {
@@ -278,6 +300,7 @@
         pw.print(prefix); pw.print("windowConfiguration="); pw.println(windowConfiguration);
         pw.print(prefix); pw.print("leash="); pw.println(leash);
         pw.print(prefix); pw.print("pictureInPictureParams="); pw.println(pictureInPictureParams);
+        pw.print(prefix); pw.print("windowType="); pw.print(windowType);
     }
 
     public void dumpDebug(ProtoOutputStream proto, long fieldId) {
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 0167147..85d4878 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -105,7 +105,6 @@
     private static native void nativeMergeTransaction(long transactionObj,
             long otherTransactionObj);
     private static native void nativeSetAnimationTransaction(long transactionObj);
-    private static native void nativeSetEarlyWakeup(long transactionObj);
     private static native void nativeSetEarlyWakeupStart(long transactionObj);
     private static native void nativeSetEarlyWakeupEnd(long transactionObj);
 
@@ -3175,23 +3174,6 @@
             return this;
         }
 
-        /**
-         * @deprecated use {@link Transaction#setEarlyWakeupStart()}
-         *
-         * Indicate that SurfaceFlinger should wake up earlier than usual as a result of this
-         * transaction. This should be used when the caller thinks that the scene is complex enough
-         * that it's likely to hit GL composition, and thus, SurfaceFlinger needs to more time in
-         * order not to miss frame deadlines.
-         * <p>
-         * Corresponds to setting ISurfaceComposer::eEarlyWakeup
-         * @hide
-         */
-        @Deprecated
-        public Transaction setEarlyWakeup() {
-            nativeSetEarlyWakeup(mNativeObject);
-            return this;
-        }
-
          /**
           * Provides a hint to SurfaceFlinger to change its offset so that SurfaceFlinger wakes up
           * earlier to compose surfaces. The caller should use this as a hint to SurfaceFlinger
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 35d5d8e..7455b8b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import static android.content.res.Resources.ID_NULL;
+import static android.view.ContentInfo.SOURCE_DRAG_AND_DROP;
 import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED;
 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_INVALID_BOUNDS;
 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_MISSING_WINDOW;
@@ -26747,6 +26748,21 @@
      * {@link android.view.DragEvent#getAction()} returns one of the action type constants defined
      * in DragEvent. The method uses these to determine what is happening in the drag and drop
      * operation.
+     * </p>
+     * <p>
+     * The default implementation returns false, except if an {@link OnReceiveContentListener}
+     * is {@link #setOnReceiveContentListener set} for this view. If an
+     * {@link OnReceiveContentListener} is set, the default implementation...
+     * <ul>
+     * <li>returns true for an
+     * {@link android.view.DragEvent#ACTION_DRAG_STARTED ACTION_DRAG_STARTED} event
+     * <li>calls {@link #performReceiveContent} for an
+     * {@link android.view.DragEvent#ACTION_DROP ACTION_DROP} event
+     * <li>returns true for an {@link android.view.DragEvent#ACTION_DROP ACTION_DROP} event, if
+     * the listener consumed some or all of the content
+     * </ul>
+     * </p>
+     *
      * @param event The {@link android.view.DragEvent} sent by the system.
      * The {@link android.view.DragEvent#getAction()} method returns an action type constant defined
      * in DragEvent, indicating the type of drag event represented by this object.
@@ -26766,6 +26782,24 @@
      * </p>
      */
     public boolean onDragEvent(DragEvent event) {
+        if (mListenerInfo == null || mListenerInfo.mOnReceiveContentListener == null) {
+            return false;
+        }
+        // Accept drag events by default if there's an OnReceiveContentListener set.
+        if (event.getAction() == DragEvent.ACTION_DRAG_STARTED) {
+            return true;
+        }
+        if (event.getAction() == DragEvent.ACTION_DROP) {
+            final DragAndDropPermissions permissions = DragAndDropPermissions.obtain(event);
+            if (permissions != null) {
+                permissions.takeTransient();
+            }
+            final ContentInfo payload = new ContentInfo.Builder(
+                    event.getClipData(), SOURCE_DRAG_AND_DROP).build();
+            ContentInfo remainingPayload = performReceiveContent(payload);
+            // Return true unless none of the payload was consumed.
+            return remainingPayload != payload;
+        }
         return false;
     }
 
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index d462f58..e4fb611 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1100,6 +1100,7 @@
                             mTempControls);
                     if (mTranslator != null) {
                         mTranslator.translateInsetsStateInScreenToAppWindow(mTempInsets);
+                        mTranslator.translateSourceControlsInScreenToAppWindow(mTempControls);
                     }
                 } catch (RemoteException e) {
                     mAdded = false;
@@ -7699,6 +7700,7 @@
         if (mTranslator != null) {
             mTranslator.translateRectInScreenToAppWindow(mTmpFrames.frame);
             mTranslator.translateInsetsStateInScreenToAppWindow(mTempInsets);
+            mTranslator.translateSourceControlsInScreenToAppWindow(mTempControls);
         }
         setFrame(mTmpFrames.frame);
         mInsetsController.onStateChanged(mTempInsets);
@@ -8158,6 +8160,7 @@
         }
         if (mTranslator != null) {
             mTranslator.translateInsetsStateInScreenToAppWindow(insetsState);
+            mTranslator.translateSourceControlsInScreenToAppWindow(activeControls);
         }
         if (insetsState != null && insetsState.getSource(ITYPE_IME).isVisible()) {
             ImeTracing.getInstance().triggerClientDump("ViewRootImpl#dispatchInsetsControlChanged",
diff --git a/core/java/android/view/inputmethod/InlineSuggestion.java b/core/java/android/view/inputmethod/InlineSuggestion.java
index b8893ce..27c637b 100644
--- a/core/java/android/view/inputmethod/InlineSuggestion.java
+++ b/core/java/android/view/inputmethod/InlineSuggestion.java
@@ -31,6 +31,7 @@
 import android.util.Size;
 import android.util.Slog;
 import android.view.SurfaceControlViewHost;
+import android.view.View;
 import android.view.ViewGroup;
 import android.widget.inline.InlineContentView;
 
@@ -38,6 +39,7 @@
 import com.android.internal.util.Parcelling;
 import com.android.internal.view.inline.IInlineContentCallback;
 import com.android.internal.view.inline.IInlineContentProvider;
+import com.android.internal.view.inline.InlineTooltipUi;
 
 import java.lang.ref.WeakReference;
 import java.util.concurrent.Executor;
@@ -75,6 +77,15 @@
     private InlineContentCallbackImpl mInlineContentCallback;
 
     /**
+     * Used to show up the inline suggestion tooltip.
+     *
+     * @hide
+     */
+    @Nullable
+    @DataClass.ParcelWith(InlineTooltipUiParceling.class)
+    private InlineTooltipUi mInlineTooltipUi;
+
+    /**
      * Creates a new {@link InlineSuggestion}, for testing purpose.
      *
      * @hide
@@ -82,7 +93,8 @@
     @TestApi
     @NonNull
     public static InlineSuggestion newInlineSuggestion(@NonNull InlineSuggestionInfo info) {
-        return new InlineSuggestion(info, null, /* inlineContentCallback */ null);
+        return new InlineSuggestion(info, null, /* inlineContentCallback */ null,
+                /* inlineTooltipUi */ null);
     }
 
     /**
@@ -92,7 +104,7 @@
      */
     public InlineSuggestion(@NonNull InlineSuggestionInfo info,
             @Nullable IInlineContentProvider contentProvider) {
-        this(info, contentProvider, /* inlineContentCallback */ null);
+        this(info, contentProvider, /* inlineContentCallback */ null, /* inlineTooltipUi */ null);
     }
 
     /**
@@ -136,9 +148,21 @@
                     "size is neither between min:" + minSize + " and max:" + maxSize
                             + ", nor wrap_content");
         }
-        mInlineContentCallback = getInlineContentCallback(context, callbackExecutor, callback);
+
+        InlineSuggestion toolTip = mInfo.getTooltip();
+        if (toolTip != null) {
+            if (mInlineTooltipUi == null) {
+                mInlineTooltipUi = new InlineTooltipUi(context);
+            }
+        } else {
+            mInlineTooltipUi = null;
+        }
+
+        mInlineContentCallback = getInlineContentCallback(context, callbackExecutor, callback,
+                mInlineTooltipUi);
         if (mContentProvider == null) {
             callbackExecutor.execute(() -> callback.accept(/* view */ null));
+            mInlineTooltipUi = null;
             return;
         }
         try {
@@ -148,6 +172,13 @@
             Slog.w(TAG, "Error creating suggestion content surface: " + e);
             callbackExecutor.execute(() -> callback.accept(/* view */ null));
         }
+        if (toolTip == null) return;
+
+        final Size tooltipSize = new Size(ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT);
+        mInfo.getTooltip().inflate(context, tooltipSize, callbackExecutor, view -> {
+            Handler.getMain().post(() -> mInlineTooltipUi.setTooltipView(view));
+        });
     }
 
     /**
@@ -162,12 +193,13 @@
     }
 
     private synchronized InlineContentCallbackImpl getInlineContentCallback(Context context,
-            Executor callbackExecutor, Consumer<InlineContentView> callback) {
+            Executor callbackExecutor, Consumer<InlineContentView> callback,
+            InlineTooltipUi inlineTooltipUi) {
         if (mInlineContentCallback != null) {
             throw new IllegalStateException("Already called #inflate()");
         }
         return new InlineContentCallbackImpl(context, mContentProvider, callbackExecutor,
-                callback);
+                callback, inlineTooltipUi);
     }
 
     /**
@@ -267,14 +299,19 @@
         @Nullable
         private Consumer<SurfaceControlViewHost.SurfacePackage> mSurfacePackageConsumer;
 
+        @Nullable
+        private InlineTooltipUi mInlineTooltipUi;
+
         InlineContentCallbackImpl(@NonNull Context context,
                 @Nullable IInlineContentProvider inlineContentProvider,
                 @NonNull @CallbackExecutor Executor callbackExecutor,
-                @NonNull Consumer<InlineContentView> callback) {
+                @NonNull Consumer<InlineContentView> callback,
+                @Nullable InlineTooltipUi inlineTooltipUi) {
             mContext = context;
             mInlineContentProvider = inlineContentProvider;
             mCallbackExecutor = callbackExecutor;
             mCallback = callback;
+            mInlineTooltipUi = inlineTooltipUi;
         }
 
         @BinderThread
@@ -305,6 +342,17 @@
                 mCallbackExecutor.execute(() -> mCallback.accept(/* view */null));
             } else {
                 mView = new InlineContentView(mContext);
+                if (mInlineTooltipUi != null) {
+                    mView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+                        @Override
+                        public void onLayoutChange(View v, int left, int top, int right,
+                                int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
+                            if (mInlineTooltipUi != null) {
+                                mInlineTooltipUi.update(mView);
+                            }
+                        }
+                    });
+                }
                 mView.setLayoutParams(new ViewGroup.LayoutParams(width, height));
                 mView.setChildSurfacePackageUpdater(getSurfacePackageUpdater());
                 mCallbackExecutor.execute(() -> mCallback.accept(mView));
@@ -425,10 +473,25 @@
         }
     }
 
+    /**
+     * This class used to provide parcelling logic for InlineContentCallbackImpl. It's intended to
+     * make this parcelling a no-op, since it can't be parceled and we don't need to parcel it.
+     */
+    private static class InlineTooltipUiParceling implements
+            Parcelling<InlineTooltipUi> {
+        @Override
+        public void parcel(InlineTooltipUi item, Parcel dest, int parcelFlags) {
+        }
+
+        @Override
+        public InlineTooltipUi unparcel(Parcel source) {
+            return null;
+        }
+    }
 
 
 
-    // Code below generated by codegen v1.0.15.
+    // Code below generated by codegen v1.0.22.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -446,18 +509,22 @@
      *
      * @param inlineContentCallback
      *   Used to keep a strong reference to the callback so it doesn't get garbage collected.
+     * @param inlineTooltipUi
+     *   Used to show up the inline suggestion tooltip.
      * @hide
      */
     @DataClass.Generated.Member
     public InlineSuggestion(
             @NonNull InlineSuggestionInfo info,
             @Nullable IInlineContentProvider contentProvider,
-            @Nullable InlineContentCallbackImpl inlineContentCallback) {
+            @Nullable InlineContentCallbackImpl inlineContentCallback,
+            @Nullable InlineTooltipUi inlineTooltipUi) {
         this.mInfo = info;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mInfo);
         this.mContentProvider = contentProvider;
         this.mInlineContentCallback = inlineContentCallback;
+        this.mInlineTooltipUi = inlineTooltipUi;
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -485,6 +552,16 @@
         return mInlineContentCallback;
     }
 
+    /**
+     * Used to show up the inline suggestion tooltip.
+     *
+     * @hide
+     */
+    @DataClass.Generated.Member
+    public @Nullable InlineTooltipUi getInlineTooltipUi() {
+        return mInlineTooltipUi;
+    }
+
     @Override
     @DataClass.Generated.Member
     public String toString() {
@@ -494,7 +571,8 @@
         return "InlineSuggestion { " +
                 "info = " + mInfo + ", " +
                 "contentProvider = " + mContentProvider + ", " +
-                "inlineContentCallback = " + mInlineContentCallback +
+                "inlineContentCallback = " + mInlineContentCallback + ", " +
+                "inlineTooltipUi = " + mInlineTooltipUi +
         " }";
     }
 
@@ -513,7 +591,8 @@
         return true
                 && java.util.Objects.equals(mInfo, that.mInfo)
                 && java.util.Objects.equals(mContentProvider, that.mContentProvider)
-                && java.util.Objects.equals(mInlineContentCallback, that.mInlineContentCallback);
+                && java.util.Objects.equals(mInlineContentCallback, that.mInlineContentCallback)
+                && java.util.Objects.equals(mInlineTooltipUi, that.mInlineTooltipUi);
     }
 
     @Override
@@ -526,6 +605,7 @@
         _hash = 31 * _hash + java.util.Objects.hashCode(mInfo);
         _hash = 31 * _hash + java.util.Objects.hashCode(mContentProvider);
         _hash = 31 * _hash + java.util.Objects.hashCode(mInlineContentCallback);
+        _hash = 31 * _hash + java.util.Objects.hashCode(mInlineTooltipUi);
         return _hash;
     }
 
@@ -540,6 +620,17 @@
         }
     }
 
+    @DataClass.Generated.Member
+    static Parcelling<InlineTooltipUi> sParcellingForInlineTooltipUi =
+            Parcelling.Cache.get(
+                    InlineTooltipUiParceling.class);
+    static {
+        if (sParcellingForInlineTooltipUi == null) {
+            sParcellingForInlineTooltipUi = Parcelling.Cache.put(
+                    new InlineTooltipUiParceling());
+        }
+    }
+
     @Override
     @DataClass.Generated.Member
     public void writeToParcel(@NonNull Parcel dest, int flags) {
@@ -549,10 +640,12 @@
         byte flg = 0;
         if (mContentProvider != null) flg |= 0x2;
         if (mInlineContentCallback != null) flg |= 0x4;
+        if (mInlineTooltipUi != null) flg |= 0x8;
         dest.writeByte(flg);
         dest.writeTypedObject(mInfo, flags);
         if (mContentProvider != null) dest.writeStrongInterface(mContentProvider);
         sParcellingForInlineContentCallback.parcel(mInlineContentCallback, dest, flags);
+        sParcellingForInlineTooltipUi.parcel(mInlineTooltipUi, dest, flags);
     }
 
     @Override
@@ -570,12 +663,14 @@
         InlineSuggestionInfo info = (InlineSuggestionInfo) in.readTypedObject(InlineSuggestionInfo.CREATOR);
         IInlineContentProvider contentProvider = (flg & 0x2) == 0 ? null : IInlineContentProvider.Stub.asInterface(in.readStrongBinder());
         InlineContentCallbackImpl inlineContentCallback = sParcellingForInlineContentCallback.unparcel(in);
+        InlineTooltipUi inlineTooltipUi = sParcellingForInlineTooltipUi.unparcel(in);
 
         this.mInfo = info;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mInfo);
         this.mContentProvider = contentProvider;
         this.mInlineContentCallback = inlineContentCallback;
+        this.mInlineTooltipUi = inlineTooltipUi;
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -595,10 +690,10 @@
     };
 
     @DataClass.Generated(
-            time = 1589396017700L,
-            codegenVersion = "1.0.15",
+            time = 1615562097666L,
+            codegenVersion = "1.0.22",
             sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestion.java",
-            inputSignatures = "private static final  java.lang.String TAG\nprivate final @android.annotation.NonNull android.view.inputmethod.InlineSuggestionInfo mInfo\nprivate final @android.annotation.Nullable com.android.internal.view.inline.IInlineContentProvider mContentProvider\nprivate @com.android.internal.util.DataClass.ParcelWith(android.view.inputmethod.InlineSuggestion.InlineContentCallbackImplParceling.class) @android.annotation.Nullable android.view.inputmethod.InlineSuggestion.InlineContentCallbackImpl mInlineContentCallback\npublic static @android.annotation.TestApi @android.annotation.NonNull android.view.inputmethod.InlineSuggestion newInlineSuggestion(android.view.inputmethod.InlineSuggestionInfo)\npublic  void inflate(android.content.Context,android.util.Size,java.util.concurrent.Executor,java.util.function.Consumer<android.widget.inline.InlineContentView>)\nprivate static  boolean isValid(int,int,int)\nprivate synchronized  android.view.inputmethod.InlineSuggestion.InlineContentCallbackImpl getInlineContentCallback(android.content.Context,java.util.concurrent.Executor,java.util.function.Consumer<android.widget.inline.InlineContentView>)\nclass InlineSuggestion extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstDefs=true, genHiddenConstructor=true)")
+            inputSignatures = "private static final  java.lang.String TAG\nprivate final @android.annotation.NonNull android.view.inputmethod.InlineSuggestionInfo mInfo\nprivate final @android.annotation.Nullable com.android.internal.view.inline.IInlineContentProvider mContentProvider\nprivate @com.android.internal.util.DataClass.ParcelWith(android.view.inputmethod.InlineSuggestion.InlineContentCallbackImplParceling.class) @android.annotation.Nullable android.view.inputmethod.InlineSuggestion.InlineContentCallbackImpl mInlineContentCallback\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(android.view.inputmethod.InlineSuggestion.InlineTooltipUiParceling.class) com.android.internal.view.inline.InlineTooltipUi mInlineTooltipUi\npublic static @android.annotation.TestApi @android.annotation.NonNull android.view.inputmethod.InlineSuggestion newInlineSuggestion(android.view.inputmethod.InlineSuggestionInfo)\npublic  void inflate(android.content.Context,android.util.Size,java.util.concurrent.Executor,java.util.function.Consumer<android.widget.inline.InlineContentView>)\nprivate static  boolean isValid(int,int,int)\nprivate synchronized  android.view.inputmethod.InlineSuggestion.InlineContentCallbackImpl getInlineContentCallback(android.content.Context,java.util.concurrent.Executor,java.util.function.Consumer<android.widget.inline.InlineContentView>,com.android.internal.view.inline.InlineTooltipUi)\nclass InlineSuggestion extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstDefs=true, genHiddenConstructor=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/view/inputmethod/InlineSuggestionInfo.java b/core/java/android/view/inputmethod/InlineSuggestionInfo.java
index 10fd0e0..5798614 100644
--- a/core/java/android/view/inputmethod/InlineSuggestionInfo.java
+++ b/core/java/android/view/inputmethod/InlineSuggestionInfo.java
@@ -73,6 +73,11 @@
     private final boolean mPinned;
 
     /**
+     * @hide
+     */
+    private final @Nullable InlineSuggestion mTooltip;
+
+    /**
      * Creates a new {@link InlineSuggestionInfo}, for testing purpose.
      *
      * @hide
@@ -84,12 +89,30 @@
             @NonNull @Source String source,
             @SuppressLint("NullableCollection")
             @Nullable String[] autofillHints, @NonNull @Type String type, boolean isPinned) {
-        return new InlineSuggestionInfo(presentationSpec, source, autofillHints, type, isPinned);
+        return new InlineSuggestionInfo(presentationSpec, source, autofillHints, type, isPinned,
+                null);
+    }
+
+    /**
+     * Creates a new {@link InlineSuggestionInfo}, for testing purpose.
+     *
+     * @hide
+     */
+    @NonNull
+    public static InlineSuggestionInfo newInlineSuggestionInfo(
+            @NonNull InlinePresentationSpec presentationSpec,
+            @NonNull @Source String source,
+            @Nullable String[] autofillHints, @NonNull @Type String type, boolean isPinned,
+            @Nullable InlineSuggestion tooltip) {
+        return new InlineSuggestionInfo(presentationSpec, source, autofillHints, type, isPinned,
+                tooltip);
     }
 
 
 
-    // Code below generated by codegen v1.0.20.
+
+
+    // Code below generated by codegen v1.0.22.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -141,7 +164,8 @@
             @NonNull @Source String source,
             @Nullable String[] autofillHints,
             @NonNull @Type String type,
-            boolean pinned) {
+            boolean pinned,
+            @Nullable InlineSuggestion tooltip) {
         this.mInlinePresentationSpec = inlinePresentationSpec;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mInlinePresentationSpec);
@@ -171,6 +195,7 @@
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mType);
         this.mPinned = pinned;
+        this.mTooltip = tooltip;
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -215,6 +240,14 @@
         return mPinned;
     }
 
+    /**
+     * @hide
+     */
+    @DataClass.Generated.Member
+    public @Nullable InlineSuggestion getTooltip() {
+        return mTooltip;
+    }
+
     @Override
     @DataClass.Generated.Member
     public String toString() {
@@ -226,7 +259,8 @@
                 "source = " + mSource + ", " +
                 "autofillHints = " + java.util.Arrays.toString(mAutofillHints) + ", " +
                 "type = " + mType + ", " +
-                "pinned = " + mPinned +
+                "pinned = " + mPinned + ", " +
+                "tooltip = " + mTooltip +
         " }";
     }
 
@@ -247,7 +281,8 @@
                 && java.util.Objects.equals(mSource, that.mSource)
                 && java.util.Arrays.equals(mAutofillHints, that.mAutofillHints)
                 && java.util.Objects.equals(mType, that.mType)
-                && mPinned == that.mPinned;
+                && mPinned == that.mPinned
+                && java.util.Objects.equals(mTooltip, that.mTooltip);
     }
 
     @Override
@@ -262,6 +297,7 @@
         _hash = 31 * _hash + java.util.Arrays.hashCode(mAutofillHints);
         _hash = 31 * _hash + java.util.Objects.hashCode(mType);
         _hash = 31 * _hash + Boolean.hashCode(mPinned);
+        _hash = 31 * _hash + java.util.Objects.hashCode(mTooltip);
         return _hash;
     }
 
@@ -274,11 +310,13 @@
         byte flg = 0;
         if (mPinned) flg |= 0x10;
         if (mAutofillHints != null) flg |= 0x4;
+        if (mTooltip != null) flg |= 0x20;
         dest.writeByte(flg);
         dest.writeTypedObject(mInlinePresentationSpec, flags);
         dest.writeString(mSource);
         if (mAutofillHints != null) dest.writeStringArray(mAutofillHints);
         dest.writeString(mType);
+        if (mTooltip != null) dest.writeTypedObject(mTooltip, flags);
     }
 
     @Override
@@ -298,6 +336,7 @@
         String source = in.readString();
         String[] autofillHints = (flg & 0x4) == 0 ? null : in.createStringArray();
         String type = in.readString();
+        InlineSuggestion tooltip = (flg & 0x20) == 0 ? null : (InlineSuggestion) in.readTypedObject(InlineSuggestion.CREATOR);
 
         this.mInlinePresentationSpec = inlinePresentationSpec;
         com.android.internal.util.AnnotationValidations.validate(
@@ -328,6 +367,7 @@
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mType);
         this.mPinned = pinned;
+        this.mTooltip = tooltip;
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -347,10 +387,10 @@
     };
 
     @DataClass.Generated(
-            time = 1604456249219L,
-            codegenVersion = "1.0.20",
+            time = 1614287616672L,
+            codegenVersion = "1.0.22",
             sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestionInfo.java",
-            inputSignatures = "public static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_AUTOFILL\npublic static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_PLATFORM\npublic static final @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String TYPE_SUGGESTION\npublic static final @android.annotation.SuppressLint @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String TYPE_ACTION\nprivate final @android.annotation.NonNull android.widget.inline.InlinePresentationSpec mInlinePresentationSpec\nprivate final @android.annotation.NonNull @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String mSource\nprivate final @android.annotation.Nullable java.lang.String[] mAutofillHints\nprivate final @android.annotation.NonNull @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String mType\nprivate final  boolean mPinned\npublic static @android.annotation.TestApi @android.annotation.NonNull android.view.inputmethod.InlineSuggestionInfo newInlineSuggestionInfo(android.widget.inline.InlinePresentationSpec,java.lang.String,java.lang.String[],java.lang.String,boolean)\nclass InlineSuggestionInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstDefs=true, genHiddenConstructor=true)")
+            inputSignatures = "public static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_AUTOFILL\npublic static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_PLATFORM\npublic static final @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String TYPE_SUGGESTION\npublic static final @android.annotation.SuppressLint @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String TYPE_ACTION\nprivate final @android.annotation.NonNull android.widget.inline.InlinePresentationSpec mInlinePresentationSpec\nprivate final @android.annotation.NonNull @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String mSource\nprivate final @android.annotation.Nullable java.lang.String[] mAutofillHints\nprivate final @android.annotation.NonNull @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String mType\nprivate final  boolean mPinned\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestion mTooltip\npublic static @android.annotation.TestApi @android.annotation.NonNull android.view.inputmethod.InlineSuggestionInfo newInlineSuggestionInfo(android.widget.inline.InlinePresentationSpec,java.lang.String,java.lang.String[],java.lang.String,boolean)\npublic static @android.annotation.NonNull android.view.inputmethod.InlineSuggestionInfo newInlineSuggestionInfo(android.widget.inline.InlinePresentationSpec,java.lang.String,java.lang.String[],java.lang.String,boolean,android.view.inputmethod.InlineSuggestion)\nclass InlineSuggestionInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstDefs=true, genHiddenConstructor=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
index 0ab4e05..e1e1755 100644
--- a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
+++ b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
@@ -106,6 +106,27 @@
     private int mHostDisplayId;
 
     /**
+     * Specifies the UI specification for the inline suggestion tooltip in the response.
+     */
+    private @Nullable InlinePresentationSpec mInlineTooltipPresentationSpec;
+
+    /**
+     * Whether the IME supports inline suggestions from the default Autofill service that
+     * provides the input view.
+     *
+     * Note: The default value is {@code true}.
+     */
+    private boolean mServiceSupported;
+
+    /**
+     * Whether the IME supports inline suggestions from the application that provides the
+     * input view.
+     *
+     * Note: The default value is {@code true}.
+     */
+    private boolean mClientSupported;
+
+    /**
      * @hide
      * @see {@link #mHostInputToken}.
      */
@@ -151,6 +172,10 @@
         for (int i = 0; i < mInlinePresentationSpecs.size(); i++) {
             mInlinePresentationSpecs.get(i).filterContentTypes();
         }
+
+        if (mInlineTooltipPresentationSpec != null) {
+            mInlineTooltipPresentationSpec.filterContentTypes();
+        }
     }
 
     private static int defaultMaxSuggestionCount() {
@@ -161,6 +186,10 @@
         return ActivityThread.currentPackageName();
     }
 
+    private static InlinePresentationSpec defaultInlineTooltipPresentationSpec() {
+        return null;
+    }
+
     /**
      * The {@link InlineSuggestionsRequest#getSupportedLocales()} now returns empty locale list when
      * it's not set, instead of the default system locale.
@@ -191,6 +220,14 @@
         return Bundle.EMPTY;
     }
 
+    private static boolean defaultServiceSupported() {
+        return true;
+    }
+
+    private static boolean defaultClientSupported() {
+        return true;
+    }
+
     /** @hide */
     abstract static class BaseBuilder {
         abstract Builder setInlinePresentationSpecs(
@@ -203,6 +240,16 @@
         abstract Builder setHostDisplayId(int value);
     }
 
+    /** @hide */
+    public boolean isServiceSupported() {
+        return mServiceSupported;
+    }
+
+    /** @hide */
+    public boolean isClientSupported() {
+        return mClientSupported;
+    }
+
 
 
     // Code below generated by codegen v1.0.22.
@@ -226,7 +273,10 @@
             @NonNull LocaleList supportedLocales,
             @NonNull Bundle extras,
             @Nullable IBinder hostInputToken,
-            int hostDisplayId) {
+            int hostDisplayId,
+            @Nullable InlinePresentationSpec inlineTooltipPresentationSpec,
+            boolean serviceSupported,
+            boolean clientSupported) {
         this.mMaxSuggestionCount = maxSuggestionCount;
         this.mInlinePresentationSpecs = inlinePresentationSpecs;
         com.android.internal.util.AnnotationValidations.validate(
@@ -242,6 +292,9 @@
                 NonNull.class, null, mExtras);
         this.mHostInputToken = hostInputToken;
         this.mHostDisplayId = hostDisplayId;
+        this.mInlineTooltipPresentationSpec = inlineTooltipPresentationSpec;
+        this.mServiceSupported = serviceSupported;
+        this.mClientSupported = clientSupported;
 
         onConstructed();
     }
@@ -324,6 +377,16 @@
         return mHostDisplayId;
     }
 
+    /**
+     * The {@link InlinePresentationSpec} for the inline suggestion tooltip in the response.
+     *
+     * @see android.service.autofill.InlinePresentation#createTooltipPresentation(Slice, InlinePresentationSpec)
+     */
+    @DataClass.Generated.Member
+    public @Nullable InlinePresentationSpec getInlineTooltipPresentationSpec() {
+        return mInlineTooltipPresentationSpec;
+    }
+
     @Override
     @DataClass.Generated.Member
     public String toString() {
@@ -337,7 +400,10 @@
                 "supportedLocales = " + mSupportedLocales + ", " +
                 "extras = " + mExtras + ", " +
                 "hostInputToken = " + mHostInputToken + ", " +
-                "hostDisplayId = " + mHostDisplayId +
+                "hostDisplayId = " + mHostDisplayId + ", " +
+                "inlineTooltipPresentationSpec = " + mInlineTooltipPresentationSpec + ", " +
+                "serviceSupported = " + mServiceSupported + ", " +
+                "clientSupported = " + mClientSupported +
         " }";
     }
 
@@ -360,7 +426,10 @@
                 && java.util.Objects.equals(mSupportedLocales, that.mSupportedLocales)
                 && extrasEquals(that.mExtras)
                 && java.util.Objects.equals(mHostInputToken, that.mHostInputToken)
-                && mHostDisplayId == that.mHostDisplayId;
+                && mHostDisplayId == that.mHostDisplayId
+                && java.util.Objects.equals(mInlineTooltipPresentationSpec, that.mInlineTooltipPresentationSpec)
+                && mServiceSupported == that.mServiceSupported
+                && mClientSupported == that.mClientSupported;
     }
 
     @Override
@@ -377,6 +446,9 @@
         _hash = 31 * _hash + java.util.Objects.hashCode(mExtras);
         _hash = 31 * _hash + java.util.Objects.hashCode(mHostInputToken);
         _hash = 31 * _hash + mHostDisplayId;
+        _hash = 31 * _hash + java.util.Objects.hashCode(mInlineTooltipPresentationSpec);
+        _hash = 31 * _hash + Boolean.hashCode(mServiceSupported);
+        _hash = 31 * _hash + Boolean.hashCode(mClientSupported);
         return _hash;
     }
 
@@ -386,9 +458,12 @@
         // You can override field parcelling by defining methods like:
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
-        byte flg = 0;
+        int flg = 0;
+        if (mServiceSupported) flg |= 0x100;
+        if (mClientSupported) flg |= 0x200;
         if (mHostInputToken != null) flg |= 0x20;
-        dest.writeByte(flg);
+        if (mInlineTooltipPresentationSpec != null) flg |= 0x80;
+        dest.writeInt(flg);
         dest.writeInt(mMaxSuggestionCount);
         dest.writeParcelableList(mInlinePresentationSpecs, flags);
         dest.writeString(mHostPackageName);
@@ -396,6 +471,7 @@
         dest.writeBundle(mExtras);
         parcelHostInputToken(dest, flags);
         dest.writeInt(mHostDisplayId);
+        if (mInlineTooltipPresentationSpec != null) dest.writeTypedObject(mInlineTooltipPresentationSpec, flags);
     }
 
     @Override
@@ -409,7 +485,9 @@
         // You can override field unparcelling by defining methods like:
         // static FieldType unparcelFieldName(Parcel in) { ... }
 
-        byte flg = in.readByte();
+        int flg = in.readInt();
+        boolean serviceSupported = (flg & 0x100) != 0;
+        boolean clientSupported = (flg & 0x200) != 0;
         int maxSuggestionCount = in.readInt();
         List<InlinePresentationSpec> inlinePresentationSpecs = new ArrayList<>();
         in.readParcelableList(inlinePresentationSpecs, InlinePresentationSpec.class.getClassLoader());
@@ -418,6 +496,7 @@
         Bundle extras = in.readBundle();
         IBinder hostInputToken = unparcelHostInputToken(in);
         int hostDisplayId = in.readInt();
+        InlinePresentationSpec inlineTooltipPresentationSpec = (flg & 0x80) == 0 ? null : (InlinePresentationSpec) in.readTypedObject(InlinePresentationSpec.CREATOR);
 
         this.mMaxSuggestionCount = maxSuggestionCount;
         this.mInlinePresentationSpecs = inlinePresentationSpecs;
@@ -434,6 +513,9 @@
                 NonNull.class, null, mExtras);
         this.mHostInputToken = hostInputToken;
         this.mHostDisplayId = hostDisplayId;
+        this.mInlineTooltipPresentationSpec = inlineTooltipPresentationSpec;
+        this.mServiceSupported = serviceSupported;
+        this.mClientSupported = clientSupported;
 
         onConstructed();
     }
@@ -466,6 +548,9 @@
         private @NonNull Bundle mExtras;
         private @Nullable IBinder mHostInputToken;
         private int mHostDisplayId;
+        private @Nullable InlinePresentationSpec mInlineTooltipPresentationSpec;
+        private boolean mServiceSupported;
+        private boolean mClientSupported;
 
         private long mBuilderFieldsSet = 0L;
 
@@ -597,10 +682,51 @@
             return this;
         }
 
+        /**
+         * The {@link InlinePresentationSpec} for the inline suggestion tooltip in the response.
+         *
+         * @see android.service.autofill.InlinePresentation#createTooltipPresentation(Slice, InlinePresentationSpec)s
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setInlineTooltipPresentationSpec(@NonNull InlinePresentationSpec value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x80;
+            mInlineTooltipPresentationSpec = value;
+            return this;
+        }
+
+        /**
+         * Whether the IME supports inline suggestions from the default Autofill service that
+         * provides the input view.
+         *
+         * Note: The default value is {@code true}.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setServiceSupported(boolean value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x100;
+            mServiceSupported = value;
+            return this;
+        }
+
+        /**
+         * Whether the IME supports inline suggestions from the application that provides the
+         * input view.
+         *
+         * Note: The default value is {@code true}.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setClientSupported(boolean value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x200;
+            mClientSupported = value;
+            return this;
+        }
+
         /** Builds the instance. This builder should not be touched after calling this! */
         public @NonNull InlineSuggestionsRequest build() {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x80; // Mark builder used
+            mBuilderFieldsSet |= 0x400; // Mark builder used
 
             if ((mBuilderFieldsSet & 0x1) == 0) {
                 mMaxSuggestionCount = defaultMaxSuggestionCount();
@@ -620,6 +746,15 @@
             if ((mBuilderFieldsSet & 0x40) == 0) {
                 mHostDisplayId = defaultHostDisplayId();
             }
+            if ((mBuilderFieldsSet & 0x80) == 0) {
+                mInlineTooltipPresentationSpec = defaultInlineTooltipPresentationSpec();
+            }
+            if ((mBuilderFieldsSet & 0x100) == 0) {
+                mServiceSupported = defaultServiceSupported();
+            }
+            if ((mBuilderFieldsSet & 0x200) == 0) {
+                mClientSupported = defaultClientSupported();
+            }
             InlineSuggestionsRequest o = new InlineSuggestionsRequest(
                     mMaxSuggestionCount,
                     mInlinePresentationSpecs,
@@ -627,12 +762,15 @@
                     mSupportedLocales,
                     mExtras,
                     mHostInputToken,
-                    mHostDisplayId);
+                    mHostDisplayId,
+                    mInlineTooltipPresentationSpec,
+                    mServiceSupported,
+                    mClientSupported);
             return o;
         }
 
         private void checkNotUsed() {
-            if ((mBuilderFieldsSet & 0x80) != 0) {
+            if ((mBuilderFieldsSet & 0x400) != 0) {
                 throw new IllegalStateException(
                         "This Builder should not be reused. Use a new Builder instance instead");
             }
@@ -640,10 +778,10 @@
     }
 
     @DataClass.Generated(
-            time = 1612206506050L,
+            time = 1615798784918L,
             codegenVersion = "1.0.22",
             sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java",
-            inputSignatures = "public static final  int SUGGESTION_COUNT_UNLIMITED\nprivate final  int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.widget.inline.InlinePresentationSpec> mInlinePresentationSpecs\nprivate @android.annotation.NonNull java.lang.String mHostPackageName\nprivate @android.annotation.NonNull android.os.LocaleList mSupportedLocales\nprivate @android.annotation.NonNull android.os.Bundle mExtras\nprivate @android.annotation.Nullable android.os.IBinder mHostInputToken\nprivate  int mHostDisplayId\nprivate static final @android.compat.annotation.ChangeId @android.compat.annotation.EnabledSince long IME_AUTOFILL_DEFAULT_SUPPORTED_LOCALES_IS_EMPTY\npublic  void setHostInputToken(android.os.IBinder)\nprivate  boolean extrasEquals(android.os.Bundle)\nprivate  void parcelHostInputToken(android.os.Parcel,int)\nprivate @android.annotation.Nullable android.os.IBinder unparcelHostInputToken(android.os.Parcel)\npublic  void setHostDisplayId(int)\nprivate  void onConstructed()\npublic  void filterContentTypes()\nprivate static  int defaultMaxSuggestionCount()\nprivate static  java.lang.String defaultHostPackageName()\nprivate static  android.os.LocaleList defaultSupportedLocales()\nprivate static @android.annotation.Nullable android.os.IBinder defaultHostInputToken()\nprivate static @android.annotation.Nullable int defaultHostDisplayId()\nprivate static @android.annotation.NonNull android.os.Bundle defaultExtras()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []")
+            inputSignatures = "public static final  int SUGGESTION_COUNT_UNLIMITED\nprivate final  int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.widget.inline.InlinePresentationSpec> mInlinePresentationSpecs\nprivate @android.annotation.NonNull java.lang.String mHostPackageName\nprivate @android.annotation.NonNull android.os.LocaleList mSupportedLocales\nprivate @android.annotation.NonNull android.os.Bundle mExtras\nprivate @android.annotation.Nullable android.os.IBinder mHostInputToken\nprivate  int mHostDisplayId\nprivate @android.annotation.Nullable android.widget.inline.InlinePresentationSpec mInlineTooltipPresentationSpec\nprivate  boolean mServiceSupported\nprivate  boolean mClientSupported\nprivate static final @android.compat.annotation.ChangeId @android.compat.annotation.EnabledSince long IME_AUTOFILL_DEFAULT_SUPPORTED_LOCALES_IS_EMPTY\npublic  void setHostInputToken(android.os.IBinder)\nprivate  boolean extrasEquals(android.os.Bundle)\nprivate  void parcelHostInputToken(android.os.Parcel,int)\nprivate @android.annotation.Nullable android.os.IBinder unparcelHostInputToken(android.os.Parcel)\npublic  void setHostDisplayId(int)\nprivate  void onConstructed()\npublic  void filterContentTypes()\nprivate static  int defaultMaxSuggestionCount()\nprivate static  java.lang.String defaultHostPackageName()\nprivate static  android.widget.inline.InlinePresentationSpec defaultInlineTooltipPresentationSpec()\nprivate static  android.os.LocaleList defaultSupportedLocales()\nprivate static @android.annotation.Nullable android.os.IBinder defaultHostInputToken()\nprivate static @android.annotation.Nullable int defaultHostDisplayId()\nprivate static @android.annotation.NonNull android.os.Bundle defaultExtras()\nprivate static  boolean defaultServiceSupported()\nprivate static  boolean defaultClientSupported()\npublic  boolean isServiceSupported()\npublic  boolean isClientSupported()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract  android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index ff4d671..9872dc0 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -462,11 +462,25 @@
      */
     @UnsupportedAppUsage
     String mCurId;
+
     /**
-     * The actual instance of the method to make calls on it.
+     * Kept for {@link UnsupportedAppUsage}.  Not officially maintained.
+     *
+     * @deprecated New code should use {@link #mCurrentInputMethodSession}.
      */
+    @Deprecated
+    @GuardedBy("mH")
+    @Nullable
     @UnsupportedAppUsage
     IInputMethodSession mCurMethod;
+
+    /**
+     * Encapsulates IPCs to the currently connected InputMethodService.
+     */
+    @Nullable
+    @GuardedBy("mH")
+    private InputMethodSessionWrapper mCurrentInputMethodSession = null;
+
     InputChannel mCurChannel;
     ImeInputEventSender mCurSender;
 
@@ -623,11 +637,8 @@
         public void finishInputAndReportToIme() {
             synchronized (mH) {
                 finishInputLocked();
-                if (mCurMethod != null) {
-                    try {
-                        mCurMethod.finishInput();
-                    } catch (RemoteException e) {
-                    }
+                if (mCurrentInputMethodSession != null) {
+                    mCurrentInputMethodSession.finishInput();
                 }
             }
         }
@@ -754,7 +765,8 @@
         @Override
         public boolean hasActiveConnection(View view) {
             synchronized (mH) {
-                if (!hasServedByInputMethodLocked(view) || mCurMethod == null) {
+                if (!hasServedByInputMethodLocked(view)
+                        || mCurrentInputMethodSession == null) {
                     return false;
                 }
 
@@ -861,7 +873,9 @@
                                 REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE;
 
                         setInputChannelLocked(res.channel);
-                        mCurMethod = res.method;
+                        mCurMethod = res.method; // for @UnsupportedAppUsage
+                        mCurrentInputMethodSession =
+                                InputMethodSessionWrapper.createOrNull(res.method);
                         mCurId = res.id;
                         mBindSequence = res.sequence;
                         mActivityViewToScreenMatrix = res.getActivityViewToScreenMatrix();
@@ -1004,7 +1018,7 @@
                         }
                         mActivityViewToScreenMatrix.setValues(matrixValues);
 
-                        if (mCursorAnchorInfo == null || mCurMethod == null
+                        if (mCursorAnchorInfo == null || mCurrentInputMethodSession == null
                                 || mServedInputConnectionWrapper == null) {
                             return;
                         }
@@ -1015,13 +1029,9 @@
                         }
                         // Since the host ActivityView is moved, we need to issue
                         // IMS#updateCursorAnchorInfo() again.
-                        try {
-                            mCurMethod.updateCursorAnchorInfo(
-                                    CursorAnchorInfo.createForAdditionalParentMatrix(
-                                            mCursorAnchorInfo, mActivityViewToScreenMatrix));
-                        } catch (RemoteException e) {
-                            Log.w(TAG, "IME died: " + mCurId, e);
-                        }
+                        mCurrentInputMethodSession.updateCursorAnchorInfo(
+                                CursorAnchorInfo.createForAdditionalParentMatrix(
+                                        mCursorAnchorInfo, mActivityViewToScreenMatrix));
                     }
                     return;
                 }
@@ -1498,7 +1508,8 @@
         setInputChannelLocked(null);
         mBindSequence = -1;
         mCurId = null;
-        mCurMethod = null;
+        mCurMethod = null; // for @UnsupportedAppUsage
+        mCurrentInputMethodSession = null;
     }
 
     void setInputChannelLocked(InputChannel channel) {
@@ -1562,11 +1573,8 @@
             }
 
             mCompletions = completions;
-            if (mCurMethod != null) {
-                try {
-                    mCurMethod.displayCompletions(mCompletions);
-                } catch (RemoteException e) {
-                }
+            if (mCurrentInputMethodSession != null) {
+                mCurrentInputMethodSession.displayCompletions(mCompletions);
             }
         }
     }
@@ -1585,11 +1593,8 @@
                 return;
             }
 
-            if (mCurMethod != null) {
-                try {
-                    mCurMethod.updateExtractedText(token, text);
-                } catch (RemoteException e) {
-                }
+            if (mCurrentInputMethodSession != null) {
+                mCurrentInputMethodSession.updateExtractedText(token, text);
             }
         }
     }
@@ -1850,11 +1855,8 @@
             if (servedView == null || servedView.getWindowToken() != windowToken) {
                 return;
             }
-            if (mCurMethod != null) {
-                try {
-                    mCurMethod.toggleSoftInput(showFlags, hideFlags);
-                } catch (RemoteException e) {
-                }
+            if (mCurrentInputMethodSession != null) {
+                mCurrentInputMethodSession.toggleSoftInput(showFlags, hideFlags);
             }
         }
     }
@@ -1875,11 +1877,8 @@
         ImeTracing.getInstance().triggerClientDump(
                 "InputMethodManager#toggleSoftInput", InputMethodManager.this,
                 null /* icProto */);
-        if (mCurMethod != null) {
-            try {
-                mCurMethod.toggleSoftInput(showFlags, hideFlags);
-            } catch (RemoteException e) {
-            }
+        if (mCurrentInputMethodSession != null) {
+            mCurrentInputMethodSession.toggleSoftInput(showFlags, hideFlags);
         }
     }
 
@@ -2062,7 +2061,8 @@
                 if (res.id != null) {
                     setInputChannelLocked(res.channel);
                     mBindSequence = res.sequence;
-                    mCurMethod = res.method;
+                    mCurMethod = res.method; // for @UnsupportedAppUsage
+                    mCurrentInputMethodSession = InputMethodSessionWrapper.createOrNull(res.method);
                     mCurId = res.id;
                 } else if (res.channel != null && res.channel != mCurChannel) {
                     res.channel.dispose();
@@ -2072,11 +2072,8 @@
                         mRestartOnNextWindowFocus = true;
                         break;
                 }
-                if (mCurMethod != null && mCompletions != null) {
-                    try {
-                        mCurMethod.displayCompletions(mCompletions);
-                    } catch (RemoteException e) {
-                    }
+                if (mCurrentInputMethodSession != null && mCompletions != null) {
+                    mCurrentInputMethodSession.displayCompletions(mCompletions);
                 }
             } catch (RemoteException e) {
                 Log.w(TAG, "IME died: " + mCurId, e);
@@ -2234,12 +2231,9 @@
         ImeTracing.getInstance().triggerClientDump("InputMethodManager#notifyImeHidden", this,
                 null /* icProto */);
         synchronized (mH) {
-            try {
-                if (mCurMethod != null && mCurRootView != null
-                        && mCurRootView.getWindowToken() == windowToken) {
-                    mCurMethod.notifyImeHidden();
-                }
-            } catch (RemoteException re) {
+            if (mCurrentInputMethodSession != null && mCurRootView != null
+                    && mCurRootView.getWindowToken() == windowToken) {
+                mCurrentInputMethodSession.notifyImeHidden();
             }
         }
     }
@@ -2284,7 +2278,7 @@
         checkFocus();
         synchronized (mH) {
             if (!hasServedByInputMethodLocked(view) || mCurrentTextBoxAttribute == null
-                    || mCurMethod == null) {
+                    || mCurrentInputMethodSession == null) {
                 return;
             }
 
@@ -2293,22 +2287,20 @@
                     || mCursorCandEnd != candidatesEnd) {
                 if (DEBUG) Log.d(TAG, "updateSelection");
 
-                try {
-                    if (DEBUG) Log.v(TAG, "SELECTION CHANGE: " + mCurMethod);
-                    final int oldSelStart = mCursorSelStart;
-                    final int oldSelEnd = mCursorSelEnd;
-                    // Update internal values before sending updateSelection to the IME, because
-                    // if it changes the text within its onUpdateSelection handler in a way that
-                    // does not move the cursor we don't want to call it again with the same values.
-                    mCursorSelStart = selStart;
-                    mCursorSelEnd = selEnd;
-                    mCursorCandStart = candidatesStart;
-                    mCursorCandEnd = candidatesEnd;
-                    mCurMethod.updateSelection(oldSelStart, oldSelEnd,
-                            selStart, selEnd, candidatesStart, candidatesEnd);
-                } catch (RemoteException e) {
-                    Log.w(TAG, "IME died: " + mCurId, e);
+                if (DEBUG) {
+                    Log.v(TAG, "SELECTION CHANGE: " + mCurrentInputMethodSession);
                 }
+                final int oldSelStart = mCursorSelStart;
+                final int oldSelEnd = mCursorSelEnd;
+                // Update internal values before sending updateSelection to the IME, because
+                // if it changes the text within its onUpdateSelection handler in a way that
+                // does not move the cursor we don't want to call it again with the same values.
+                mCursorSelStart = selStart;
+                mCursorSelEnd = selEnd;
+                mCursorCandStart = candidatesStart;
+                mCursorCandEnd = candidatesEnd;
+                mCurrentInputMethodSession.updateSelection(
+                        oldSelStart, oldSelEnd, selStart, selEnd, candidatesStart, candidatesEnd);
             }
         }
     }
@@ -2342,15 +2334,11 @@
         checkFocus();
         synchronized (mH) {
             if (!hasServedByInputMethodLocked(view) || mCurrentTextBoxAttribute == null
-                    || mCurMethod == null) {
+                    || mCurrentInputMethodSession == null) {
                 return;
             }
-            try {
-                if (DEBUG) Log.v(TAG, "onViewClicked: " + focusChanged);
-                mCurMethod.viewClicked(focusChanged);
-            } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
-            }
+            if (DEBUG) Log.v(TAG, "onViewClicked: " + focusChanged);
+            mCurrentInputMethodSession.viewClicked(focusChanged);
         }
     }
 
@@ -2411,21 +2399,16 @@
         checkFocus();
         synchronized (mH) {
             if (!hasServedByInputMethodLocked(view) || mCurrentTextBoxAttribute == null
-                    || mCurMethod == null) {
+                    || mCurrentInputMethodSession == null) {
                 return;
             }
 
             mTmpCursorRect.set(left, top, right, bottom);
             if (!mCursorRect.equals(mTmpCursorRect)) {
-                if (DEBUG) Log.d(TAG, "updateCursor");
+                if (DEBUG) Log.d(TAG, "updateCursor: " + mCurrentInputMethodSession);
 
-                try {
-                    if (DEBUG) Log.v(TAG, "CURSOR CHANGE: " + mCurMethod);
-                    mCurMethod.updateCursor(mTmpCursorRect);
-                    mCursorRect.set(mTmpCursorRect);
-                } catch (RemoteException e) {
-                    Log.w(TAG, "IME died: " + mCurId, e);
-                }
+                mCurrentInputMethodSession.updateCursor(mTmpCursorRect);
+                mCursorRect.set(mTmpCursorRect);
             }
         }
     }
@@ -2448,7 +2431,7 @@
         checkFocus();
         synchronized (mH) {
             if (!hasServedByInputMethodLocked(view) || mCurrentTextBoxAttribute == null
-                    || mCurMethod == null) {
+                    || mCurrentInputMethodSession == null) {
                 return;
             }
             // If immediate bit is set, we will call updateCursorAnchorInfo() even when the data has
@@ -2465,21 +2448,16 @@
                 return;
             }
             if (DEBUG) Log.v(TAG, "updateCursorAnchorInfo: " + cursorAnchorInfo);
-            try {
-                if (mActivityViewToScreenMatrix != null) {
-                    mCurMethod.updateCursorAnchorInfo(
-                            CursorAnchorInfo.createForAdditionalParentMatrix(
-                                    cursorAnchorInfo, mActivityViewToScreenMatrix));
-                } else {
-                    mCurMethod.updateCursorAnchorInfo(cursorAnchorInfo);
-                }
-                mCursorAnchorInfo = cursorAnchorInfo;
-                // Clear immediate bit (if any).
-                mRequestUpdateCursorAnchorInfoMonitorMode &=
-                        ~InputConnection.CURSOR_UPDATE_IMMEDIATE;
-            } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
+            if (mActivityViewToScreenMatrix != null) {
+                mCurrentInputMethodSession.updateCursorAnchorInfo(
+                        CursorAnchorInfo.createForAdditionalParentMatrix(
+                            cursorAnchorInfo, mActivityViewToScreenMatrix));
+            } else {
+                mCurrentInputMethodSession.updateCursorAnchorInfo(cursorAnchorInfo);
             }
+            mCursorAnchorInfo = cursorAnchorInfo;
+            // Clear immediate bit (if any).
+            mRequestUpdateCursorAnchorInfoMonitorMode &= ~InputConnection.CURSOR_UPDATE_IMMEDIATE;
         }
     }
 
@@ -2505,15 +2483,11 @@
         checkFocus();
         synchronized (mH) {
             if (!hasServedByInputMethodLocked(view) || mCurrentTextBoxAttribute == null
-                    || mCurMethod == null) {
+                    || mCurrentInputMethodSession == null) {
                 return;
             }
-            try {
-                if (DEBUG) Log.v(TAG, "APP PRIVATE COMMAND " + action + ": " + data);
-                mCurMethod.appPrivateCommand(action, data);
-            } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
-            }
+            if (DEBUG) Log.v(TAG, "APP PRIVATE COMMAND " + action + ": " + data);
+            mCurrentInputMethodSession.appPrivateCommand(action, data);
         }
     }
 
@@ -2671,7 +2645,7 @@
     public int dispatchInputEvent(InputEvent event, Object token,
             FinishedInputEventCallback callback, Handler handler) {
         synchronized (mH) {
-            if (mCurMethod != null) {
+            if (mCurrentInputMethodSession != null) {
                 if (event instanceof KeyEvent) {
                     KeyEvent keyEvent = (KeyEvent)event;
                     if (keyEvent.getAction() == KeyEvent.ACTION_DOWN
@@ -2682,7 +2656,9 @@
                     }
                 }
 
-                if (DEBUG) Log.v(TAG, "DISPATCH INPUT EVENT: " + mCurMethod);
+                if (DEBUG) {
+                    Log.v(TAG, "DISPATCH INPUT EVENT: " + mCurrentInputMethodSession);
+                }
 
                 PendingEvent p = obtainPendingEventLocked(
                         event, token, mCurId, callback, handler);
@@ -2772,8 +2748,7 @@
                 return DISPATCH_IN_PROGRESS;
             }
 
-            Log.w(TAG, "Unable to send input event to IME: "
-                    + mCurId + " dropping: " + event);
+            Log.w(TAG, "Unable to send input event to IME: " + mCurId + " dropping: " + event);
         }
         return DISPATCH_NOT_HANDLED;
     }
@@ -3230,7 +3205,11 @@
                 + " mBindSequence=" + mBindSequence
                 + " mCurId=" + mCurId);
         p.println("  mFullscreenMode=" + mFullscreenMode);
-        p.println("  mCurMethod=" + mCurMethod);
+        if (mCurrentInputMethodSession != null) {
+            p.println("  mCurMethod=" + mCurrentInputMethodSession);
+        } else {
+            p.println("  mCurMethod= null");
+        }
         p.println("  mCurRootView=" + mCurRootView);
         p.println("  mServedView=" + getServedViewLocked());
         p.println("  mNextServedView=" + getNextServedViewLocked());
@@ -3346,7 +3325,7 @@
      */
     @GuardedBy("mH")
     public void dumpDebug(ProtoOutputStream proto, ProtoOutputStream icProto) {
-        if (mCurMethod == null) {
+        if (mCurrentInputMethodSession == null) {
             return;
         }
 
diff --git a/core/java/android/view/inputmethod/InputMethodSessionWrapper.java b/core/java/android/view/inputmethod/InputMethodSessionWrapper.java
new file mode 100644
index 0000000..c4a3773
--- /dev/null
+++ b/core/java/android/view/inputmethod/InputMethodSessionWrapper.java
@@ -0,0 +1,163 @@
+/*
+ * 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.inputmethod;
+
+import android.annotation.AnyThread;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.view.IInputMethodSession;
+
+/**
+ * This class wrap the {@link IInputMethodSession} object from {@link InputMethodManager}.
+ * Using current {@link IInputMethodSession} object to communicate with
+ * {@link android.inputmethodservice.InputMethodService}.
+ */
+final class InputMethodSessionWrapper {
+
+    private static final String TAG = "InputMethodSessionWrapper";
+
+    /**
+     * The actual instance of the method to make calls on it.
+     */
+    @NonNull
+    private final IInputMethodSession mSession;
+
+    private InputMethodSessionWrapper(@NonNull IInputMethodSession inputMethodSession) {
+        mSession = inputMethodSession;
+    }
+
+    /**
+     * Create a {@link InputMethodSessionWrapper} instance if applicability.
+     *
+     * @param inputMethodSession {@link IInputMethodSession} object to be wrapped.
+     * @return an instance of {@link InputMethodSessionWrapper} if {@code inputMethodSession} is not
+     *         {@code null}. {@code null} otherwise.
+     */
+    @Nullable
+    public static InputMethodSessionWrapper createOrNull(
+            @NonNull IInputMethodSession inputMethodSession) {
+        return inputMethodSession != null ? new InputMethodSessionWrapper(inputMethodSession)
+                : null;
+    }
+
+    @AnyThread
+    void finishInput() {
+        try {
+            mSession.finishInput();
+        } catch (RemoteException e) {
+            Log.w(TAG, "IME died", e);
+        }
+    }
+
+    @AnyThread
+    void updateCursorAnchorInfo(CursorAnchorInfo cursorAnchorInfo) {
+        try {
+            mSession.updateCursorAnchorInfo(cursorAnchorInfo);
+        } catch (RemoteException e) {
+            Log.w(TAG, "IME died", e);
+        }
+    }
+
+    @AnyThread
+    void displayCompletions(CompletionInfo[] completions) {
+        try {
+            mSession.displayCompletions(completions);
+        } catch (RemoteException e) {
+            Log.w(TAG, "IME died", e);
+        }
+    }
+
+    @AnyThread
+    void updateExtractedText(int token, ExtractedText text) {
+        try {
+            mSession.updateExtractedText(token, text);
+        } catch (RemoteException e) {
+            Log.w(TAG, "IME died", e);
+        }
+    }
+
+    @AnyThread
+    void toggleSoftInput(int showFlags, int hideFlags) {
+        try {
+            mSession.toggleSoftInput(showFlags, hideFlags);
+        } catch (RemoteException e) {
+            Log.w(TAG, "IME died", e);
+        }
+    }
+
+    @AnyThread
+    void appPrivateCommand(String action, Bundle data) {
+        try {
+            mSession.appPrivateCommand(action, data);
+        } catch (RemoteException e) {
+            Log.w(TAG, "IME died", e);
+        }
+    }
+
+    @AnyThread
+    void notifyImeHidden() {
+        try {
+            mSession.notifyImeHidden();
+        } catch (RemoteException e) {
+            Log.w(TAG, "IME died", e);
+        }
+    }
+
+    @AnyThread
+    void viewClicked(boolean focusChanged) {
+        try {
+            mSession.viewClicked(focusChanged);
+        } catch (RemoteException e) {
+            Log.w(TAG, "IME died", e);
+        }
+    }
+
+    @AnyThread
+    void updateCursor(Rect newCursor) {
+        try {
+            mSession.updateCursor(newCursor);
+        } catch (RemoteException e) {
+            Log.w(TAG, "IME died", e);
+        }
+    }
+
+    @AnyThread
+    void updateSelection(int oldSelStart, int oldSelEnd, int selStart, int selEnd,
+            int candidatesStart, int candidatesEnd) {
+        try {
+            mSession.updateSelection(
+                    oldSelStart, oldSelEnd, selStart, selEnd, candidatesStart, candidatesEnd);
+        } catch (RemoteException e) {
+            Log.w(TAG, "IME died", e);
+        }
+    }
+
+    /**
+     * @return {@link IInputMethodSession#toString()} as a debug string.
+     */
+    @AnyThread
+    @NonNull
+    @Override
+    public String toString() {
+        return mSession.toString();
+    }
+}
diff --git a/core/java/android/view/textservice/SpellCheckerSession.java b/core/java/android/view/textservice/SpellCheckerSession.java
index ba58b65..a449cf1 100644
--- a/core/java/android/view/textservice/SpellCheckerSession.java
+++ b/core/java/android/view/textservice/SpellCheckerSession.java
@@ -16,6 +16,8 @@
 
 package android.view.textservice;
 
+import android.annotation.BinderThread;
+import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Binder;
 import android.os.Build;
@@ -27,6 +29,7 @@
 import android.util.Log;
 import android.view.inputmethod.InputMethodManager;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.textservice.ISpellCheckerSession;
 import com.android.internal.textservice.ISpellCheckerSessionListener;
 import com.android.internal.textservice.ITextServicesSessionListener;
@@ -35,6 +38,7 @@
 
 import java.util.LinkedList;
 import java.util.Queue;
+import java.util.concurrent.Executor;
 
 /**
  * The SpellCheckerSession interface provides the per client functionality of SpellCheckerService.
@@ -102,38 +106,26 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     private final SpellCheckerSessionListener mSpellCheckerSessionListener;
     private final SpellCheckerSessionListenerImpl mSpellCheckerSessionListenerImpl;
+    private final Executor mExecutor;
 
     private final CloseGuard mGuard = CloseGuard.get();
 
-    /** Handler that will execute the main tasks */
-    private final Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_ON_GET_SUGGESTION_MULTIPLE:
-                    handleOnGetSuggestionsMultiple((SuggestionsInfo[]) msg.obj);
-                    break;
-                case MSG_ON_GET_SUGGESTION_MULTIPLE_FOR_SENTENCE:
-                    handleOnGetSentenceSuggestionsMultiple((SentenceSuggestionsInfo[]) msg.obj);
-                    break;
-            }
-        }
-    };
-
     /**
      * Constructor
      * @hide
      */
     public SpellCheckerSession(
-            SpellCheckerInfo info, TextServicesManager tsm, SpellCheckerSessionListener listener) {
+            SpellCheckerInfo info, TextServicesManager tsm, SpellCheckerSessionListener listener,
+            Executor executor) {
         if (info == null || listener == null || tsm == null) {
             throw new NullPointerException();
         }
         mSpellCheckerInfo = info;
-        mSpellCheckerSessionListenerImpl = new SpellCheckerSessionListenerImpl(mHandler);
+        mSpellCheckerSessionListenerImpl = new SpellCheckerSessionListenerImpl(this);
         mInternalListener = new InternalListener(mSpellCheckerSessionListenerImpl);
         mTextServicesManager = tsm;
         mSpellCheckerSessionListener = listener;
+        mExecutor = executor;
 
         mGuard.open("finishSession");
     }
@@ -219,12 +211,13 @@
                 textInfos, suggestionsLimit, sequentialWords);
     }
 
-    private void handleOnGetSuggestionsMultiple(SuggestionsInfo[] suggestionInfos) {
-        mSpellCheckerSessionListener.onGetSuggestions(suggestionInfos);
+    void handleOnGetSuggestionsMultiple(SuggestionsInfo[] suggestionsInfos) {
+        mExecutor.execute(() -> mSpellCheckerSessionListener.onGetSuggestions(suggestionsInfos));
     }
 
-    private void handleOnGetSentenceSuggestionsMultiple(SentenceSuggestionsInfo[] suggestionInfos) {
-        mSpellCheckerSessionListener.onGetSentenceSuggestions(suggestionInfos);
+    void handleOnGetSentenceSuggestionsMultiple(SentenceSuggestionsInfo[] suggestionsInfos) {
+        mExecutor.execute(() ->
+                mSpellCheckerSessionListener.onGetSentenceSuggestions(suggestionsInfos));
     }
 
     private static final class SpellCheckerSessionListenerImpl
@@ -249,7 +242,8 @@
         }
 
         private final Queue<SpellCheckerParams> mPendingTasks = new LinkedList<>();
-        private Handler mHandler;
+        @GuardedBy("SpellCheckerSessionListenerImpl.this")
+        private SpellCheckerSession mSpellCheckerSession;
 
         private static final int STATE_WAIT_CONNECTION = 0;
         private static final int STATE_CONNECTED = 1;
@@ -270,8 +264,8 @@
         private HandlerThread mThread;
         private Handler mAsyncHandler;
 
-        public SpellCheckerSessionListenerImpl(Handler handler) {
-            mHandler = handler;
+        SpellCheckerSessionListenerImpl(SpellCheckerSession spellCheckerSession) {
+            mSpellCheckerSession = spellCheckerSession;
         }
 
         private static class SpellCheckerParams {
@@ -349,6 +343,7 @@
             }
         }
 
+        @GuardedBy("SpellCheckerSessionListenerImpl.this")
         private void processCloseLocked() {
             if (DBG) Log.d(TAG, "entering processCloseLocked:"
                     + " session" + (mISpellCheckerSession != null ? ".hashCode()=#"
@@ -358,7 +353,7 @@
             if (mThread != null) {
                 mThread.quit();
             }
-            mHandler = null;
+            mSpellCheckerSession = null;
             mPendingTasks.clear();
             mThread = null;
             mAsyncHandler = null;
@@ -502,23 +497,30 @@
             processTask(session, scp, false);
         }
 
+        @BinderThread
         @Override
         public void onGetSuggestions(SuggestionsInfo[] results) {
-            synchronized (this) {
-                if (mHandler != null) {
-                    mHandler.sendMessage(Message.obtain(mHandler,
-                            MSG_ON_GET_SUGGESTION_MULTIPLE, results));
-                }
+            SpellCheckerSession session = getSpellCheckerSession();
+            if (session != null) {
+                // Lock should not be held when calling callback, in order to avoid deadlock.
+                session.handleOnGetSuggestionsMultiple(results);
             }
         }
 
+        @BinderThread
         @Override
         public void onGetSentenceSuggestions(SentenceSuggestionsInfo[] results) {
-            synchronized (this) {
-                if (mHandler != null) {
-                    mHandler.sendMessage(Message.obtain(mHandler,
-                            MSG_ON_GET_SUGGESTION_MULTIPLE_FOR_SENTENCE, results));
-                }
+            SpellCheckerSession session = getSpellCheckerSession();
+            if (session != null) {
+                // Lock should not be held when calling callback, in order to avoid deadlock.
+                session.handleOnGetSentenceSuggestionsMultiple(results);
+            }
+        }
+
+        @Nullable
+        private SpellCheckerSession getSpellCheckerSession() {
+            synchronized (SpellCheckerSessionListenerImpl.this) {
+                return mSpellCheckerSession;
             }
         }
     }
diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java
index 6fb01a3..bf91cca 100644
--- a/core/java/android/view/textservice/TextServicesManager.java
+++ b/core/java/android/view/textservice/TextServicesManager.java
@@ -16,6 +16,7 @@
 
 package android.view.textservice;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SuppressLint;
@@ -25,6 +26,8 @@
 import android.content.Context;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ServiceManager.ServiceNotFoundException;
@@ -37,8 +40,11 @@
 import com.android.internal.textservice.ITextServicesManager;
 
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
+import java.util.Objects;
+import java.util.concurrent.Executor;
 
 /**
  * System API to the overall text services, which arbitrates interaction between applications
@@ -160,10 +166,12 @@
      * {@link SuggestionsInfo#RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS} will be passed to the spell
      * checker as supported attributes.
      *
-     * @see #newSpellCheckerSession(Bundle, Locale, SpellCheckerSessionListener, boolean, int)
+     * @see #newSpellCheckerSession(Locale, boolean, int, Bundle, Executor,
+     *      SpellCheckerSessionListener)
      * @param bundle A bundle to pass to the spell checker.
      * @param locale The locale for the spell checker.
      * @param listener A spell checker session lister for getting results from the spell checker.
+     *                 The listener will be called on the calling thread.
      * @param referToSpellCheckerLanguageSettings If true, the session for one of enabled
      *                                            languages in settings will be used.
      * @return A spell checker session from the spell checker.
@@ -173,10 +181,15 @@
             @Nullable Locale locale,
             @NonNull SpellCheckerSessionListener listener,
             boolean referToSpellCheckerLanguageSettings) {
-        return newSpellCheckerSession(bundle, locale, listener, referToSpellCheckerLanguageSettings,
-                SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY
-                        | SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO
-                        | SuggestionsInfo.RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS);
+        // Attributes existed before {@link #newSpellCheckerSession(Locale, boolean, int, Bundle,
+        // Executor, SpellCheckerSessionListener)} was introduced.
+        int supportedAttributes = SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY
+                | SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO
+                | SuggestionsInfo.RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS;
+        // Using the implicit looper to preserve the old behavior.
+        Executor executor = new HandlerExecutor(new Handler());
+        return newSpellCheckerSession(locale, referToSpellCheckerLanguageSettings,
+                supportedAttributes, bundle, executor, listener);
     }
 
     /**
@@ -190,25 +203,28 @@
      * language only (e.g. "en"), the specified locale in Settings (e.g. "en_US") will be
      * selected.
      *
-     * @param bundle A bundle to pass to the spell checker.
      * @param locale The locale for the spell checker.
-     * @param listener A spell checker session lister for getting results from a spell checker.
      * @param referToSpellCheckerLanguageSettings If true, the session for one of enabled
      *                                            languages in settings will be used.
      * @param supportedAttributes A union of {@link SuggestionsInfo} attributes that the spell
      *                            checker can set in the spell checking results.
+     * @param bundle A bundle for passing implementation-specific extra parameters for the spell
+     *               checker. You can check the current spell checker package by
+     *               {@link #getCurrentSpellCheckerInfo()}.
+     * @param executor An executor to call the listener on.
+     * @param listener A spell checker session lister for getting results from a spell checker.
      * @return The spell checker session of the spell checker.
      */
     @Nullable
     public SpellCheckerSession newSpellCheckerSession(
-            @SuppressLint("NullableCollection") @Nullable Bundle bundle,
             @SuppressLint("UseIcu") @Nullable Locale locale,
-            @NonNull SpellCheckerSessionListener listener,
-            @SuppressLint("ListenerLast") boolean referToSpellCheckerLanguageSettings,
-            @SuppressLint("ListenerLast") @SuggestionsInfo.ResultAttrs int supportedAttributes) {
-        if (listener == null) {
-            throw new NullPointerException();
-        }
+            boolean referToSpellCheckerLanguageSettings,
+            @SuggestionsInfo.ResultAttrs int supportedAttributes,
+            @Nullable Bundle bundle,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull SpellCheckerSessionListener listener) {
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(listener);
         if (!referToSpellCheckerLanguageSettings && locale == null) {
             throw new IllegalArgumentException("Locale should not be null if you don't refer"
                     + " settings.");
@@ -258,7 +274,7 @@
         if (subtypeInUse == null) {
             return null;
         }
-        final SpellCheckerSession session = new SpellCheckerSession(sci, this, listener);
+        final SpellCheckerSession session = new SpellCheckerSession(sci, this, listener, executor);
         try {
             mService.getSpellCheckerService(mUserId, sci.getId(), subtypeInUse.getLocale(),
                     session.getTextServicesSessionListener(),
@@ -288,15 +304,15 @@
     }
 
     /**
-     * Retrieve the list of currently enabled spell checkers, or null if there is none.
+     * Retrieve the list of currently enabled spell checkers.
      *
      * @return The list of currently enabled spell checkers.
      */
-    @Nullable
-    @SuppressLint("NullableCollection")
+    @NonNull
     public List<SpellCheckerInfo> getEnabledSpellCheckerInfos() {
         final SpellCheckerInfo[] enabledSpellCheckers = getEnabledSpellCheckers();
-        return enabledSpellCheckers != null ? Arrays.asList(enabledSpellCheckers) : null;
+        return enabledSpellCheckers != null
+                ? Arrays.asList(enabledSpellCheckers) : Collections.emptyList();
     }
 
     /**
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index 3c41112..5f55887 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -130,7 +130,11 @@
     public @interface EdgeEffectType {
     }
 
-    private static final float DEFAULT_MAX_STRETCH_INTENSITY = 0.08f;
+    private static final float LINEAR_STRETCH_INTENSITY = 0.03f;
+
+    private static final float EXP_STRETCH_INTENSITY = 0.02f;
+
+    private static final float SCROLL_DIST_AFFECTED_BY_EXP_STRETCH = 0.4f;
 
     @SuppressWarnings("UnusedDeclaration")
     private static final String TAG = "EdgeEffect";
@@ -176,9 +180,6 @@
 
     private long mStartTime;
     private float mDuration;
-    private float mStretchIntensity = DEFAULT_MAX_STRETCH_INTENSITY;
-    private float mStretchDistanceFraction = 1f;
-    private float mStretchDistance = -1f;
 
     private final Interpolator mInterpolator = new DecelerateInterpolator();
 
@@ -269,16 +270,6 @@
     }
 
     /**
-     * Configure the distance in pixels to stretch the content. This is only consumed as part
-     * if {@link #setType(int)} is set to {@link #TYPE_STRETCH}
-     * @param stretchDistance Stretch distance in pixels when the target View is overscrolled
-     * @hide
-     */
-    public void setStretchDistance(float stretchDistance) {
-        mStretchDistance = stretchDistance;
-    }
-
-    /**
      * Reports if this EdgeEffect's animation is finished. If this method returns false
      * after a call to {@link #draw(Canvas)} the host widget should schedule another
      * drawing pass to continue the animation.
@@ -520,13 +511,6 @@
     }
 
     /**
-     * @hide
-     */
-    public void setMaxStretchIntensity(float stretchIntensity) {
-        mStretchIntensity = stretchIntensity;
-    }
-
-    /**
      * Set or clear the blend mode. A blend mode defines how source pixels
      * (generated by a drawing command) are composited with the destination pixels
      * (content of the render target).
@@ -642,22 +626,19 @@
             // assume rotations of increments of 90 degrees
             float x = mTmpPoints[10] - mTmpPoints[8];
             float width = right - left;
-            float vecX = Math.max(-1f, Math.min(1f, x / width));
+            float vecX = dampStretchVector(Math.max(-1f, Math.min(1f, x / width)));
             float y = mTmpPoints[11] - mTmpPoints[9];
             float height = bottom - top;
-            float vecY = Math.max(-1f, Math.min(1f, y / height));
+            float vecY = dampStretchVector(Math.max(-1f, Math.min(1f, y / height)));
             renderNode.stretch(
                     left,
                     top,
                     right,
                     bottom,
-                    vecX * mStretchIntensity,
-                    vecY * mStretchIntensity,
-                    // TODO (njawad/mount) figure out proper stretch distance from UX
-                    //  for now leverage placeholder logic if no stretch distance is provided to
-                    //  consume the displacement ratio times the minimum of the width or height
-                    mStretchDistance > 0 ? mStretchDistance :
-                            (mStretchDistanceFraction * Math.max(mWidth, mHeight))
+                    vecX,
+                    vecY,
+                    mWidth,
+                    mHeight
             );
         }
 
@@ -794,4 +775,13 @@
         return Math.abs(mVelocity) < VELOCITY_THRESHOLD
                 && Math.abs(displacement) < VALUE_THRESHOLD;
     }
+
+    private float dampStretchVector(float normalizedVec) {
+        float sign = normalizedVec > 0 ? 1f : -1f;
+        float overscroll = Math.abs(normalizedVec);
+        float linearIntensity = LINEAR_STRETCH_INTENSITY * overscroll;
+        double scalar = Math.E / SCROLL_DIST_AFFECTED_BY_EXP_STRETCH;
+        double expIntensity = EXP_STRETCH_INTENSITY * (1 - Math.exp(-overscroll * scalar));
+        return sign * (float) (linearIntensity + expIntensity);
+    }
 }
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index bf552e2..23915e0 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -249,26 +249,6 @@
     }
 
     /**
-     * API used for prototyping stretch effect parameters in framework sample apps
-     * @hide
-     */
-    public void setEdgeEffectIntensity(float intensity) {
-        mEdgeGlowLeft.setMaxStretchIntensity(intensity);
-        mEdgeGlowRight.setMaxStretchIntensity(intensity);
-        invalidate();
-    }
-
-    /**
-     * API used for prototyping stretch effect parameters in the framework sample apps
-     * @hide
-     */
-    public void setStretchDistance(float distance) {
-        mEdgeGlowLeft.setStretchDistance(distance);
-        mEdgeGlowRight.setStretchDistance(distance);
-        invalidate();
-    }
-
-    /**
      * Sets the right edge effect color.
      *
      * @param color The color for the right edge effect.
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 0cedcea..319e788 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -5338,10 +5338,21 @@
     }
 
     /** @hide */
-    public boolean canRecycleView(View v) {
+    public boolean canRecycleView(@Nullable View v) {
+        if (v == null) {
+            return false;
+        }
+        Integer previousLayoutId = (Integer) v.getTag(R.id.widget_frame);
+        if (previousLayoutId == null) {
+            return false;
+        }
         Integer overrideIdTag = (Integer) v.getTag(R.id.remote_views_override_id);
         int overrideId = overrideIdTag == null ? View.NO_ID : overrideIdTag;
-        return (Integer) v.getTag(R.id.widget_frame) == getLayoutId() && mViewId == overrideId;
+        // If mViewId is View.NO_ID, we only recycle if overrideId is also View.NO_ID.
+        // Otherwise, it might be that, on a previous iteration, the view's ID was set to
+        // something else, and it should now be reset to the ID defined in the XML layout file,
+        // whatever it is.
+        return previousLayoutId == getLayoutId() && mViewId == overrideId;
     }
 
     // Note: topLevel should be true only for calls on the topLevel RemoteViews, internal calls
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 3006729..65f3da7 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -281,26 +281,6 @@
     }
 
     /**
-     * API used for prototyping stretch effect parameters in framework sample apps
-     * @hide
-     */
-    public void setEdgeEffectIntensity(float intensity) {
-        mEdgeGlowTop.setMaxStretchIntensity(intensity);
-        mEdgeGlowBottom.setMaxStretchIntensity(intensity);
-        invalidate();
-    }
-
-    /**
-     * API used for prototyping stretch effect parameters in the framework sample apps
-     * @hide
-     */
-    public void setStretchDistance(float distance) {
-        mEdgeGlowTop.setStretchDistance(distance);
-        mEdgeGlowBottom.setStretchDistance(distance);
-        invalidate();
-    }
-
-    /**
      * Sets the bottom edge effect color.
      *
      * @param color The color for the bottom edge effect.
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index 2464b4a..a63305e 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -126,14 +126,14 @@
                 || mTextServicesManager.getCurrentSpellCheckerSubtype(true) == null) {
             mSpellCheckerSession = null;
         } else {
+            int supportedAttributes = SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY
+                    | SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO
+                    | SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_GRAMMAR_ERROR
+                    | SuggestionsInfo.RESULT_ATTR_DONT_SHOW_UI_FOR_SUGGESTIONS;
             mSpellCheckerSession = mTextServicesManager.newSpellCheckerSession(
+                    mCurrentLocale, false, supportedAttributes,
                     null /* Bundle not currently used by the textServicesManager */,
-                    mCurrentLocale, this,
-                    false /* means any available languages from current spell checker */,
-                    SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY
-                            | SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO
-                            | SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_GRAMMAR_ERROR
-                            | SuggestionsInfo.RESULT_ATTR_DONT_SHOW_UI_FOR_SUGGESTIONS);
+                    mTextView.getContext().getMainExecutor(), this);
         }
 
         // Restore SpellCheckSpans in pool
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index dba7fa9..940a3c9 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -13071,11 +13071,37 @@
         return getLayout().getOffsetForHorizontal(line, x);
     }
 
+    /**
+     * Handles drag events sent by the system following a call to
+     * {@link android.view.View#startDragAndDrop(ClipData,DragShadowBuilder,Object,int)
+     * startDragAndDrop()}.
+     *
+     * <p>If this text view is not editable, delegates to the default {@link View#onDragEvent}
+     * implementation.
+     *
+     * <p>If this text view is editable, accepts all drag actions (returns true for an
+     * {@link android.view.DragEvent#ACTION_DRAG_STARTED ACTION_DRAG_STARTED} event and all
+     * subsequent drag events). While the drag is in progress, updates the cursor position
+     * to follow the touch location. Once a drop event is received, handles content insertion
+     * via {@link #performReceiveContent}.
+     *
+     * @param event The {@link android.view.DragEvent} sent by the system.
+     * The {@link android.view.DragEvent#getAction()} method returns an action type constant
+     * defined in DragEvent, indicating the type of drag event represented by this object.
+     * @return Returns true if this text view is editable and delegates to super otherwise.
+     * See {@link View#onDragEvent}.
+     */
     @Override
     public boolean onDragEvent(DragEvent event) {
+        if (mEditor == null || !mEditor.hasInsertionController()) {
+            // If this TextView is not editable, defer to the default View implementation. This
+            // will check for the presence of an OnReceiveContentListener and accept/reject
+            // drag events depending on whether the listener is/isn't set.
+            return super.onDragEvent(event);
+        }
         switch (event.getAction()) {
             case DragEvent.ACTION_DRAG_STARTED:
-                return mEditor != null && mEditor.hasInsertionController();
+                return true;
 
             case DragEvent.ACTION_DRAG_ENTERED:
                 TextView.this.requestFocus();
diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java
index da445b8..3709aa1 100644
--- a/core/java/android/window/SplashScreenView.java
+++ b/core/java/android/window/SplashScreenView.java
@@ -17,18 +17,16 @@
 
 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
 
-import android.animation.Animator;
-import android.animation.ValueAnimator;
 import android.annotation.ColorInt;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
+import android.app.Activity;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Rect;
-import android.graphics.drawable.Animatable;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
@@ -70,6 +68,7 @@
 
     private boolean mNotCopyable;
     private int mInitBackgroundColor;
+    private int mInitIconBackgroundColor;
     private View mIconView;
     private Bitmap mParceledIconBitmap;
     private View mBrandingImageView;
@@ -77,10 +76,8 @@
     private long mIconAnimationDuration;
     private long mIconAnimationStart;
 
-    private Animatable mAnimatableIcon;
-    private ValueAnimator mAnimator;
-    private Runnable mAnimationFinishListener;
-    private Consumer<Canvas> mOnDrawCallback;
+    // The host activity when transfer view to it.
+    private Activity mHostActivity;
     // cache original window and status
     private Window mWindow;
     private boolean mDrawBarBackground;
@@ -95,6 +92,7 @@
         private final Context mContext;
         private int mIconSize;
         private @ColorInt int mBackgroundColor;
+        private @ColorInt int mIconBackground;
         private Bitmap mParceledIconBitmap;
         private Drawable mIconDrawable;
         private int mBrandingImageWidth;
@@ -115,6 +113,7 @@
         public Builder createFromParcel(SplashScreenViewParcelable parcelable) {
             mIconSize = parcelable.getIconSize();
             mBackgroundColor = parcelable.getBackgroundColor();
+            mIconBackground = parcelable.getIconBackground();
             if (parcelable.mIconBitmap != null) {
                 mIconDrawable = new BitmapDrawable(mContext.getResources(), parcelable.mIconBitmap);
                 mParceledIconBitmap = parcelable.mIconBitmap;
@@ -155,6 +154,14 @@
         }
 
         /**
+         * Set the background color for the icon.
+         */
+        public Builder setIconBackground(int color) {
+            mIconBackground = color;
+            return this;
+        }
+
+        /**
          * Set the animation duration if icon is animatable.
          */
         public Builder setAnimationDuration(int duration) {
@@ -180,6 +187,7 @@
             final SplashScreenView view = (SplashScreenView)
                     layoutInflater.inflate(R.layout.splash_screen_view, null, false);
             view.mInitBackgroundColor = mBackgroundColor;
+            view.mInitIconBackgroundColor = mIconBackground;
             view.setBackgroundColor(mBackgroundColor);
             view.mIconView = view.findViewById(R.id.splashscreen_icon_view);
             view.mBrandingImageView = view.findViewById(R.id.splashscreen_branding_view);
@@ -267,43 +275,15 @@
     }
 
     void initIconAnimation(Drawable iconDrawable, long duration) {
-        if (iconDrawable instanceof Animatable) {
-            mAnimatableIcon = (Animatable) iconDrawable;
-            mAnimator = ValueAnimator.ofInt(0, 1);
-            mAnimator.setDuration(duration);
-            mAnimator.addListener(new Animator.AnimatorListener() {
-                @Override
-                public void onAnimationStart(Animator animation) {
-                    mIconAnimationStart = SystemClock.uptimeMillis();
-                    mAnimatableIcon.start();
-                }
-
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    mAnimatableIcon.stop();
-                }
-
-                @Override
-                public void onAnimationCancel(Animator animation) {
-                    mAnimatableIcon.stop();
-                }
-
-                @Override
-                public void onAnimationRepeat(Animator animation) {
-                    // do not repeat
-                    mAnimatableIcon.stop();
-                }
-            });
+        if (!(iconDrawable instanceof SplashscreenIconDrawable)) {
+            return;
         }
+        SplashscreenIconDrawable aniDrawable = (SplashscreenIconDrawable) iconDrawable;
+        aniDrawable.prepareAnimate(duration, this::animationStartCallback);
     }
 
-    /**
-     * @hide
-     */
-    public void startIntroAnimation() {
-        if (mAnimatableIcon != null) {
-            mAnimator.start();
-        }
+    private void animationStartCallback(long startAt) {
+        mIconAnimationStart = startAt;
     }
 
     /**
@@ -334,6 +314,17 @@
             restoreSystemUIColors();
             mWindow = null;
         }
+        if (mHostActivity != null) {
+            mHostActivity.detachSplashScreenView();
+        }
+    }
+
+    /**
+     * Called when this view is attached to an activity.
+     * @hide
+     */
+    public void attachHostActivity(Activity activity) {
+        mHostActivity = activity;
     }
 
     /**
@@ -391,6 +382,15 @@
     }
 
     /**
+     * Get the icon background color
+     * @hide
+     */
+    @TestApi
+    public @ColorInt int getIconBackgroundColor() {
+        return mInitIconBackgroundColor;
+    }
+
+    /**
      * Get the initial background color of this view.
      * @hide
      */
@@ -399,12 +399,30 @@
     }
 
     /**
+     * A lightweight Drawable object to make the view drawing faster and keep this
+     * drawable masked by config_icon_mask.
+     * @hide
+     */
+    public abstract static class SplashscreenIconDrawable extends Drawable {
+        /**
+         * Prepare the animation if this drawable also be animatable.
+         * @param duration The animation duration.
+         * @param startListener The callback listener used to receive the start of the animation.
+         * @return true if this drawable object can also be animated and it can be played now.
+         */
+        protected boolean prepareAnimate(long duration, Consumer<Long> startListener) {
+            return false;
+        }
+    }
+
+    /**
      * Use to create {@link SplashScreenView} object across process.
      * @hide
      */
     public static class SplashScreenViewParcelable implements Parcelable {
         private int mIconSize;
         private int mBackgroundColor;
+        private int mIconBackground;
 
         private Bitmap mIconBitmap;
         private int mBrandingWidth;
@@ -418,7 +436,7 @@
             ViewGroup.LayoutParams params = view.getIconView().getLayoutParams();
             mIconSize = params.height;
             mBackgroundColor = view.getInitBackgroundColor();
-
+            mIconBackground = view.getIconBackgroundColor();
             mIconBitmap = copyDrawable(view.getIconView().getBackground());
             mBrandingBitmap = copyDrawable(view.getBrandingView().getBackground());
             params = view.getBrandingView().getLayoutParams();
@@ -459,6 +477,7 @@
             mBrandingBitmap = source.readTypedObject(Bitmap.CREATOR);
             mIconAnimationStart = source.readLong();
             mIconAnimationDuration = source.readLong();
+            mIconBackground = source.readInt();
         }
 
         @Override
@@ -476,6 +495,7 @@
             dest.writeTypedObject(mBrandingBitmap, flags);
             dest.writeLong(mIconAnimationStart);
             dest.writeLong(mIconAnimationDuration);
+            dest.writeInt(mIconBackground);
         }
 
         public static final @NonNull Parcelable.Creator<SplashScreenViewParcelable> CREATOR =
@@ -509,5 +529,9 @@
         int getBackgroundColor() {
             return mBackgroundColor;
         }
+
+        int getIconBackground() {
+            return mIconBackground;
+        }
     }
 }
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 499ce25..a0b4e24 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -16,6 +16,7 @@
 
 package android.window;
 
+import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
 import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_NONE;
@@ -31,6 +32,7 @@
 import android.graphics.Rect;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.WindowManager;
 
@@ -284,6 +286,8 @@
         private final Rect mEndAbsBounds = new Rect();
         private final Point mEndRelOffset = new Point();
         private ActivityManager.RunningTaskInfo mTaskInfo = null;
+        private int mStartRotation = ROTATION_UNDEFINED;
+        private int mEndRotation = ROTATION_UNDEFINED;
 
         public Change(@Nullable WindowContainerToken container, @NonNull SurfaceControl leash) {
             mContainer = container;
@@ -301,6 +305,8 @@
             mEndAbsBounds.readFromParcel(in);
             mEndRelOffset.readFromParcel(in);
             mTaskInfo = in.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR);
+            mStartRotation = in.readInt();
+            mEndRotation = in.readInt();
         }
 
         /** Sets the parent of this change's container. The parent must be a participant or null. */
@@ -341,6 +347,12 @@
             mTaskInfo = taskInfo;
         }
 
+        /** Sets the start and end rotation of this container. */
+        public void setRotation(@Surface.Rotation int start, @Surface.Rotation int end) {
+            mStartRotation = start;
+            mEndRotation = end;
+        }
+
         /** @return the container that is changing. May be null if non-remotable (eg. activity) */
         @Nullable
         public WindowContainerToken getContainer() {
@@ -404,6 +416,14 @@
             return mTaskInfo;
         }
 
+        public int getStartRotation() {
+            return mStartRotation;
+        }
+
+        public int getEndRotation() {
+            return mEndRotation;
+        }
+
         @Override
         /** @hide */
         public void writeToParcel(@NonNull Parcel dest, int flags) {
@@ -416,6 +436,8 @@
             mEndAbsBounds.writeToParcel(dest, flags);
             mEndRelOffset.writeToParcel(dest, flags);
             dest.writeTypedObject(mTaskInfo, flags);
+            dest.writeInt(mStartRotation);
+            dest.writeInt(mEndRotation);
         }
 
         @NonNull
@@ -442,7 +464,8 @@
         public String toString() {
             return "{" + mContainer + "(" + mParent + ") leash=" + mLeash
                     + " m=" + modeToString(mMode) + " f=" + flagsToString(mFlags) + " sb="
-                    + mStartAbsBounds + " eb=" + mEndAbsBounds + " eo=" + mEndRelOffset + "}";
+                    + mStartAbsBounds + " eb=" + mEndAbsBounds + " eo=" + mEndRelOffset + " r="
+                    + mStartRotation + "->" + mEndRotation + "}";
         }
     }
 }
diff --git a/core/java/com/android/internal/app/OWNERS b/core/java/com/android/internal/app/OWNERS
index 7ade05c..e6c911e 100644
--- a/core/java/com/android/internal/app/OWNERS
+++ b/core/java/com/android/internal/app/OWNERS
@@ -3,6 +3,9 @@
 per-file *Chooser* = file:/packages/SystemUI/OWNERS
 per-file SimpleIconFactory.java = file:/packages/SystemUI/OWNERS
 per-file NetInitiatedActivity.java = file:/location/java/android/location/OWNERS
-per-file IVoice* = file:/core/java/android/service/voice/OWNERS
-per-file *Hotword* = file:/core/java/android/service/voice/OWNERS
 per-file *BatteryStats* = file:/BATTERY_STATS_OWNERS
+
+# Voice Interaction
+per-file *Assist* = file:/core/java/android/service/voice/OWNERS
+per-file *Hotword* = file:/core/java/android/service/voice/OWNERS
+per-file *Voice* = file:/core/java/android/service/voice/OWNERS
diff --git a/core/java/com/android/internal/notification/SystemNotificationChannels.java b/core/java/com/android/internal/notification/SystemNotificationChannels.java
index 2237efc..2f40d3b 100644
--- a/core/java/com/android/internal/notification/SystemNotificationChannels.java
+++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java
@@ -58,6 +58,7 @@
     public static String SYSTEM_CHANGES = "SYSTEM_CHANGES";
     public static String DO_NOT_DISTURB = "DO_NOT_DISTURB";
     public static String ACCESSIBILITY_MAGNIFICATION = "ACCESSIBILITY_MAGNIFICATION";
+    public static String ACCESSIBILITY_SECURITY_POLICY = "ACCESSIBILITY_SECURITY_POLICY";
 
     public static void createAll(Context context) {
         final NotificationManager nm = context.getSystemService(NotificationManager.class);
@@ -199,6 +200,12 @@
         newFeaturePrompt.setBlockable(true);
         channelsList.add(newFeaturePrompt);
 
+        final NotificationChannel accessibilitySecurityPolicyChannel = new NotificationChannel(
+                ACCESSIBILITY_SECURITY_POLICY,
+                context.getString(R.string.notification_channel_accessibility_security_policy),
+                NotificationManager.IMPORTANCE_LOW);
+        channelsList.add(accessibilitySecurityPolicyChannel);
+
         nm.createNotificationChannels(channelsList);
     }
 
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 33b55ac..7f87885 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -11492,10 +11492,10 @@
                 return;
             }
 
-            final ArrayMap<Uid, Double> uidEstimatedConsumptionMah =
+            final SparseDoubleArray uidEstimatedConsumptionMah =
                     (mGlobalMeasuredEnergyStats != null
                             && mWifiPowerCalculator != null && consumedChargeUC > 0) ?
-                            new ArrayMap<>() : null;
+                            new SparseDoubleArray() : null;
             double totalEstimatedConsumptionMah = 0;
 
             SparseLongArray rxPackets = new SparseLongArray();
@@ -11583,7 +11583,7 @@
                             }
                         }
 
-                        addDoubleToUidMap(uidEstimatedConsumptionMah, u,
+                        uidEstimatedConsumptionMah.add(u.getUid(),
                                 mWifiPowerCalculator.calcPowerWithoutControllerDataMah(
                                         entry.rxPackets, entry.txPackets,
                                         uidRunningMs, uidScanMs, uidBatchScanMs));
@@ -11709,7 +11709,7 @@
                     if (uidEstimatedConsumptionMah != null) {
                         double uidEstMah = mWifiPowerCalculator.calcPowerFromControllerDataMah(
                                 scanRxTimeSinceMarkMs, scanTxTimeSinceMarkMs, myIdleTimeMs);
-                        addDoubleToUidMap(uidEstimatedConsumptionMah, uid, uidEstMah);
+                        uidEstimatedConsumptionMah.add(uid.getUid(), uidEstMah);
                     }
                 }
 
@@ -11731,7 +11731,7 @@
                     uid.getOrCreateWifiControllerActivityLocked().getTxTimeCounters()[0]
                             .addCountLocked(myTxTimeMs);
                     if (uidEstimatedConsumptionMah != null) {
-                        addDoubleToUidMap(uidEstimatedConsumptionMah, uid,
+                        uidEstimatedConsumptionMah.add(uid.getUid(),
                                 mWifiPowerCalculator.calcPowerFromControllerDataMah(
                                         0, myTxTimeMs, 0));
                     }
@@ -11750,7 +11750,7 @@
                     uid.getOrCreateWifiControllerActivityLocked().getRxTimeCounter()
                             .addCountLocked(myRxTimeMs);
                     if (uidEstimatedConsumptionMah != null) {
-                        addDoubleToUidMap(uidEstimatedConsumptionMah, uid,
+                        uidEstimatedConsumptionMah.add(uid.getUid(),
                                 mWifiPowerCalculator.calcPowerFromControllerDataMah(
                                         myRxTimeMs, 0, 0));
                     }
@@ -12086,10 +12086,10 @@
             Slog.d(TAG, "  Idle Time:  " + idleTimeMs + " ms");
         }
 
-        final ArrayMap<Uid, Double> uidEstimatedConsumptionMah =
+        final SparseDoubleArray uidEstimatedConsumptionMah =
                 (mGlobalMeasuredEnergyStats != null
                         && mBluetoothPowerCalculator != null && consumedChargeUC > 0) ?
-                        new ArrayMap<>() : null;
+                        new SparseDoubleArray() : null;
 
         long totalScanTimeMs = 0;
 
@@ -12150,7 +12150,7 @@
                 counter.getTxTimeCounters()[0].addCountLocked(scanTimeTxSinceMarkMs);
 
                 if (uidEstimatedConsumptionMah != null) {
-                    addDoubleToUidMap(uidEstimatedConsumptionMah, u,
+                    uidEstimatedConsumptionMah.add(u.getUid(),
                             mBluetoothPowerCalculator.calculatePowerMah(
                                     scanTimeRxSinceMarkMs, scanTimeTxSinceMarkMs, 0));
                 }
@@ -12217,7 +12217,7 @@
                     counter.getRxTimeCounter().addCountLocked(timeRxMs);
 
                     if (uidEstimatedConsumptionMah != null) {
-                        addDoubleToUidMap(uidEstimatedConsumptionMah, u,
+                        uidEstimatedConsumptionMah.add(u.getUid(),
                                 mBluetoothPowerCalculator.calculatePowerMah(timeRxMs, 0, 0));
                     }
                 }
@@ -12230,7 +12230,7 @@
                     counter.getTxTimeCounters()[0].addCountLocked(timeTxMs);
 
                     if (uidEstimatedConsumptionMah != null) {
-                        addDoubleToUidMap(uidEstimatedConsumptionMah, u,
+                        uidEstimatedConsumptionMah.add(u.getUid(),
                                 mBluetoothPowerCalculator.calculatePowerMah(0, timeTxMs, 0));
                     }
                 }
@@ -12452,7 +12452,7 @@
         // If multidisplay becomes a reality, this is probably more reasonable than pooling.
 
         // On the first pass, collect total time since mark so that we can normalize power.
-        final ArrayMap<Uid, Double> fgTimeUsArray = new ArrayMap<>();
+        final SparseDoubleArray fgTimeUsArray = new SparseDoubleArray();
         final long elapsedRealtimeUs = elapsedRealtimeMs * 1000;
         // TODO(b/175726779): Update and optimize the algorithm (e.g. avoid iterating over ALL uids)
         final int uidStatsSize = mUidStats.size();
@@ -12460,7 +12460,7 @@
             final Uid uid = mUidStats.valueAt(i);
             final long fgTimeUs = uid.markProcessForegroundTimeUs(elapsedRealtimeMs, true);
             if (fgTimeUs == 0) continue;
-            fgTimeUsArray.put(uid, (double) fgTimeUs);
+            fgTimeUsArray.put(uid.getUid(), (double) fgTimeUs);
         }
         distributeEnergyToUidsLocked(powerBucket, chargeUC, fgTimeUsArray, 0);
     }
@@ -12523,10 +12523,11 @@
      * <p>A consequence of minRatioDenominator is that the sum over all uids might be less than
      * totalConsumedChargeUC. This is intentional; the remainder is purposefully unnaccounted rather
      * than incorrectly blamed on uids, and implies unknown (non-uid) sources of drain.
+     *
+     * <p>All uids in ratioNumerators must exist in mUidStats already.
      */
-    // TODO(b/182845832): Use some sort of "SparseDoubleArray" instead of ArrayMap<Uid, Double>.
     private void distributeEnergyToUidsLocked(@StandardPowerBucket int bucket,
-            long totalConsumedChargeUC, ArrayMap<Uid, Double> ratioNumerators,
+            long totalConsumedChargeUC, SparseDoubleArray ratioNumerators,
             double minRatioDenominator) {
 
         // If the sum of all app usage was greater than the total, use that instead:
@@ -12538,7 +12539,7 @@
         if (ratioDenominator <= 0) return;
 
         for (int i = ratioNumerators.size() - 1; i >= 0; i--) {
-            final Uid uid = ratioNumerators.keyAt(i);
+            final Uid uid = getAvailableUidStatsLocked(ratioNumerators.keyAt(i));
             final double ratioNumerator = ratioNumerators.valueAt(i);
             final long uidActualUC
                     = (long) (totalConsumedChargeUC * ratioNumerator / ratioDenominator + 0.5);
@@ -12546,15 +12547,79 @@
         }
     }
 
-    /** Adds the summand to the value stored in uidMap for the given uid. */
-    // TODO(b/182845832): Use some sort of "SparseDoubleArray" instead of ArrayMap<Uid, Double>.
-    private static void addDoubleToUidMap(ArrayMap<Uid, Double> uidMap, Uid uid, double summand) {
-        if (uidMap == null) return;
-        final Double oldVal = uidMap.get(uid);
-        if (oldVal != null) {
-            summand += oldVal;
+    /**
+     * SparseDoubleArray map integers to doubles.
+     * Its implementation is the same as that of {@link SparseLongArray}; see there for details.
+     *
+     * @see SparseLongArray
+     */
+    private static class SparseDoubleArray {
+        /**
+         * The int->double map, but storing the doubles as longs using
+         * {@link Double.doubleToRawLongBits(double)}.
+         */
+        private final SparseLongArray mValues = new SparseLongArray();
+
+        /**
+         * Gets the double mapped from the specified key, or <code>0</code>
+         * if no such mapping has been made.
+         */
+        public double get(int key) {
+            if (mValues.indexOfKey(key) >= 0) {
+                return Double.longBitsToDouble(mValues.get(key));
+            }
+            return 0;
         }
-        uidMap.put(uid, summand);
+
+        /**
+         * Adds a mapping from the specified key to the specified value,
+         * replacing the previous mapping from the specified key if there
+         * was one.
+         */
+        public void put(int key, double value) {
+            mValues.put(key, Double.doubleToRawLongBits(value));
+        }
+
+        /**
+         * Adds a mapping from the specified key to the specified value,
+         * <b>adding</b> to the previous mapping from the specified key if there
+         * was one.
+         */
+        public void add(int key, double summand) {
+            final double oldValue = get(key);
+            put(key, oldValue + summand);
+        }
+
+        /**
+         * Returns the number of key-value mappings that this SparseDoubleArray
+         * currently stores.
+         */
+        public int size() {
+            return mValues.size();
+        }
+
+        /**
+         * Given an index in the range <code>0...size()-1</code>, returns
+         * the key from the <code>index</code>th key-value mapping that this
+         * SparseDoubleArray stores.
+         *
+         * @see SparseLongArray#keyAt(int)
+         */
+        public int keyAt(int index) {
+            return mValues.keyAt(index);
+        }
+
+        /**
+         * Given an index in the range <code>0...size()-1</code>, returns
+         * the value from the <code>index</code>th key-value mapping that this
+         * SparseDoubleArray stores.
+         *
+         * @see SparseLongArray#valueAt(int)
+         */
+        public double valueAt(int index) {
+            return Double.longBitsToDouble(mValues.valueAt(index));
+        }
+
     }
 
     /**
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 47b0f8c..2458fe3 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -41,7 +41,6 @@
 import android.os.ZygoteProcess;
 import android.os.storage.StorageManager;
 import android.provider.DeviceConfig;
-import android.security.keystore.AndroidKeyStoreProvider;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.OsConstants;
@@ -74,7 +73,6 @@
 import java.io.InputStreamReader;
 import java.security.Provider;
 import java.security.Security;
-import java.util.Optional;
 
 /**
  * Startup class for the zygote process.
@@ -227,17 +225,7 @@
         // AndroidKeyStoreProvider.install() manipulates the list of JCA providers to insert
         // preferred providers. Note this is not done via security.properties as the JCA providers
         // are not on the classpath in the case of, for example, raw dalvikvm runtimes.
-        // TODO b/171305684 This code is used to conditionally enable the installation of the
-        //      Keystore 2.0 provider to enable teams adjusting to Keystore 2.0 at their own
-        //      pace. This code will be removed when all calling code was adjusted to
-        //      Keystore 2.0.
-        Optional<Boolean> keystore2_enabled =
-                android.sysprop.Keystore2Properties.keystore2_enabled();
-        if (keystore2_enabled.isPresent() && keystore2_enabled.get()) {
-            android.security.keystore2.AndroidKeyStoreProvider.install();
-        } else {
-            AndroidKeyStoreProvider.install();
-        }
+        android.security.keystore2.AndroidKeyStoreProvider.install();
         Log.i(TAG, "Installed AndroidKeyStoreProvider in "
                 + (SystemClock.uptimeMillis() - startTime) + "ms.");
         Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index fea0751..f19a123 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -21,6 +21,7 @@
 import android.graphics.Rect;
 import android.hardware.biometrics.IBiometricSysuiReceiver;
 import android.hardware.biometrics.PromptInfo;
+import android.hardware.fingerprint.IUdfpsHbmListener;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.service.notification.StatusBarNotification;
@@ -156,6 +157,11 @@
     void hideAuthenticationDialog();
 
     /**
+     * Sets an instance of IUdfpsHbmListener for UdfpsController.
+     */
+    void setUdfpsHbmListener(in IUdfpsHbmListener listener);
+
+    /**
      * Notifies System UI that the display is ready to show system decorations.
      */
     void onDisplayReady(int displayId);
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 2e25ea3..c8a91d8 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -21,6 +21,7 @@
 import android.graphics.Rect;
 import android.hardware.biometrics.IBiometricSysuiReceiver;
 import android.hardware.biometrics.PromptInfo;
+import android.hardware.fingerprint.IUdfpsHbmListener;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.UserHandle;
@@ -121,6 +122,11 @@
     void hideAuthenticationDialog();
 
     /**
+     * Sets an instance of IUdfpsHbmListener for UdfpsController.
+     */
+    void setUdfpsHbmListener(in IUdfpsHbmListener listener);
+
+    /**
      * Show a warning that the device is about to go to sleep due to user inactivity.
      */
     void showInattentiveSleepWarning();
diff --git a/core/java/com/android/internal/view/inline/InlineTooltipUi.java b/core/java/com/android/internal/view/inline/InlineTooltipUi.java
new file mode 100644
index 0000000..5ec8b30
--- /dev/null
+++ b/core/java/com/android/internal/view/inline/InlineTooltipUi.java
@@ -0,0 +1,337 @@
+/*
+ * 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.view.inline;
+
+import static android.view.autofill.Helper.sVerbose;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.graphics.drawable.Drawable;
+import android.transition.Transition;
+import android.util.Slog;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.widget.PopupWindow;
+import android.widget.inline.InlineContentView;
+
+import java.io.PrintWriter;
+
+/**
+ * UI container for the inline suggestion tooltip.
+ */
+public final class InlineTooltipUi extends PopupWindow implements AutoCloseable {
+    private static final String TAG = "InlineTooltipUi";
+
+    private final WindowManager mWm;
+    private final ViewGroup mContentContainer;
+
+    private boolean mShowing;
+
+    private WindowManager.LayoutParams mWindowLayoutParams;
+
+    private final View.OnAttachStateChangeListener mAnchorOnAttachStateChangeListener =
+            new View.OnAttachStateChangeListener() {
+                @Override
+                public void onViewAttachedToWindow(View v) {
+                    /* ignore - handled by the super class */
+                }
+
+                @Override
+                public void onViewDetachedFromWindow(View v) {
+                    dismiss();
+                }
+            };
+
+    private final View.OnLayoutChangeListener mAnchoredOnLayoutChangeListener =
+            new View.OnLayoutChangeListener() {
+                int mHeight;
+                @Override
+                public void onLayoutChange(View v, int left, int top, int right, int bottom,
+                        int oldLeft, int oldTop, int oldRight, int oldBottom) {
+                    if (mHeight != bottom - top) {
+                        mHeight = bottom - top;
+                        adjustPosition();
+                    }
+                }
+            };
+
+    public InlineTooltipUi(@NonNull Context context) {
+        mContentContainer = new LinearLayout(new ContextWrapper(context));
+        mWm = context.getSystemService(WindowManager.class);
+
+        setTouchModal(false);
+        setOutsideTouchable(true);
+        setInputMethodMode(INPUT_METHOD_NOT_NEEDED);
+        setFocusable(false);
+    }
+
+    /**
+     * Sets the content view for inline suggestions tooltip
+     * @param v the content view of {@link android.widget.inline.InlineContentView}
+     */
+    public void setTooltipView(@NonNull InlineContentView v) {
+        mContentContainer.removeAllViews();
+        mContentContainer.addView(v);
+        mContentContainer.setVisibility(View.VISIBLE);
+    }
+
+    @Override
+    public void close() {
+        hide();
+    }
+
+    @Override
+    protected boolean hasContentView() {
+        return true;
+    }
+
+    @Override
+    protected boolean hasDecorView() {
+        return true;
+    }
+
+    @Override
+    protected WindowManager.LayoutParams getDecorViewLayoutParams() {
+        return mWindowLayoutParams;
+    }
+
+    /**
+     * The effective {@code update} method that should be called by its clients.
+     */
+    public void update(View anchor) {
+        // set to the application type with the highest z-order
+        setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL);
+
+        // The first time to show up, the height of tooltip is zero,
+        // so set the offset Y to 2 * anchor height.
+        final int achoredHeight = mContentContainer.getHeight();
+        final int offsetY = (achoredHeight == 0)
+                ? -anchor.getHeight() << 1 : -anchor.getHeight() - achoredHeight;
+        if (!isShowing()) {
+            setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
+            setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
+            showAsDropDown(anchor, 0 , offsetY, Gravity.TOP | Gravity.CENTER_HORIZONTAL);
+        } else {
+            update(anchor, 0 , offsetY, WindowManager.LayoutParams.WRAP_CONTENT,
+                    WindowManager.LayoutParams.WRAP_CONTENT);
+        }
+    }
+
+    @Override
+    protected void update(View anchor, WindowManager.LayoutParams params) {
+        // update content view for the anchor is scrolling
+        if (anchor.isVisibleToUser()) {
+            show(params);
+        } else {
+            hide();
+        }
+    }
+
+    @Override
+    public void showAsDropDown(View anchor, int xoff, int yoff, int gravity) {
+        if (isShowing()) {
+            return;
+        }
+
+        setShowing(true);
+        setDropDown(true);
+        attachToAnchor(anchor, xoff, yoff, gravity);
+        final WindowManager.LayoutParams p = mWindowLayoutParams = createPopupLayoutParams(
+                anchor.getWindowToken());
+        final boolean aboveAnchor = findDropDownPosition(anchor, p, xoff, yoff,
+                p.width, p.height, gravity, getAllowScrollingAnchorParent());
+        updateAboveAnchor(aboveAnchor);
+        p.accessibilityIdOfAnchor = anchor.getAccessibilityViewId();
+        p.packageName = anchor.getContext().getPackageName();
+        show(p);
+    }
+
+    @Override
+    protected void attachToAnchor(View anchor, int xoff, int yoff, int gravity) {
+        super.attachToAnchor(anchor, xoff, yoff, gravity);
+        anchor.addOnAttachStateChangeListener(mAnchorOnAttachStateChangeListener);
+    }
+
+    @Override
+    protected void detachFromAnchor() {
+        final View anchor = getAnchor();
+        if (anchor != null) {
+            anchor.removeOnAttachStateChangeListener(mAnchorOnAttachStateChangeListener);
+        }
+        super.detachFromAnchor();
+    }
+
+    @Override
+    public void dismiss() {
+        if (!isShowing() || isTransitioningToDismiss()) {
+            return;
+        }
+
+        setShowing(false);
+        setTransitioningToDismiss(true);
+
+        hide();
+        detachFromAnchor();
+        if (getOnDismissListener() != null) {
+            getOnDismissListener().onDismiss();
+        }
+    }
+
+    private void adjustPosition() {
+        View anchor = getAnchor();
+        if (anchor == null) return;
+        update(anchor);
+    }
+
+    private void show(WindowManager.LayoutParams params) {
+        if (sVerbose) {
+            Slog.v(TAG, "show()");
+        }
+        mWindowLayoutParams = params;
+
+        try {
+            params.packageName = "android";
+            params.setTitle("Autofill Inline Tooltip"); // Title is set for debugging purposes
+            if (!mShowing) {
+                params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+                mContentContainer.addOnLayoutChangeListener(mAnchoredOnLayoutChangeListener);
+                mWm.addView(mContentContainer, params);
+                mShowing = true;
+            } else {
+                mWm.updateViewLayout(mContentContainer, params);
+            }
+        } catch (WindowManager.BadTokenException e) {
+            Slog.d(TAG, "Failed with token " + params.token + " gone.");
+        } catch (IllegalStateException e) {
+            // WM throws an ISE if mContentView was added twice; this should never happen -
+            // since show() and hide() are always called in the UIThread - but when it does,
+            // it should not crash the system.
+            Slog.wtf(TAG, "Exception showing window " + params, e);
+        }
+    }
+
+    private void hide() {
+        if (sVerbose) {
+            Slog.v(TAG, "hide()");
+        }
+        try {
+            if (mShowing) {
+                mContentContainer.removeOnLayoutChangeListener(mAnchoredOnLayoutChangeListener);
+                mWm.removeView(mContentContainer);
+                mShowing = false;
+            }
+        } catch (IllegalStateException e) {
+            // WM might thrown an ISE when removing the mContentView; this should never
+            // happen - since show() and hide() are always called in the UIThread - but if it
+            // does, it should not crash the system.
+            Slog.e(TAG, "Exception hiding window ", e);
+        }
+    }
+
+    @Override
+    public int getAnimationStyle() {
+        throw new IllegalStateException("You can't call this!");
+    }
+
+    @Override
+    public Drawable getBackground() {
+        throw new IllegalStateException("You can't call this!");
+    }
+
+    @Override
+    public View getContentView() {
+        throw new IllegalStateException("You can't call this!");
+    }
+
+    @Override
+    public float getElevation() {
+        throw new IllegalStateException("You can't call this!");
+    }
+
+    @Override
+    public Transition getEnterTransition() {
+        throw new IllegalStateException("You can't call this!");
+    }
+
+    @Override
+    public Transition getExitTransition() {
+        throw new IllegalStateException("You can't call this!");
+    }
+
+    @Override
+    public void setBackgroundDrawable(Drawable background) {
+        throw new IllegalStateException("You can't call this!");
+    }
+
+    @Override
+    public void setContentView(View contentView) {
+        if (contentView != null) {
+            throw new IllegalStateException("You can't call this!");
+        }
+    }
+
+    @Override
+    public void setElevation(float elevation) {
+        throw new IllegalStateException("You can't call this!");
+    }
+
+    @Override
+    public void setEnterTransition(Transition enterTransition) {
+        throw new IllegalStateException("You can't call this!");
+    }
+
+    @Override
+    public void setExitTransition(Transition exitTransition) {
+        throw new IllegalStateException("You can't call this!");
+    }
+
+    @Override
+    public void setTouchInterceptor(View.OnTouchListener l) {
+        throw new IllegalStateException("You can't call this!");
+    }
+
+    /**
+     * Dumps status
+     */
+    public void dump(@NonNull PrintWriter pw, @Nullable String prefix) {
+
+        pw.print(prefix);
+
+        if (mContentContainer != null) {
+            pw.print(prefix); pw.print("Window: ");
+            final String prefix2 = prefix + "  ";
+            pw.println();
+            pw.print(prefix2); pw.print("showing: "); pw.println(mShowing);
+            pw.print(prefix2); pw.print("view: "); pw.println(mContentContainer);
+            if (mWindowLayoutParams != null) {
+                pw.print(prefix2); pw.print("params: "); pw.println(mWindowLayoutParams);
+            }
+            pw.print(prefix2); pw.print("screen coordinates: ");
+            if (mContentContainer == null) {
+                pw.println("N/A");
+            } else {
+                final int[] coordinates = mContentContainer.getLocationOnScreen();
+                pw.print(coordinates[0]); pw.print("x"); pw.println(coordinates[1]);
+            }
+        }
+    }
+}
diff --git a/core/java/com/android/internal/widget/ViewPager.java b/core/java/com/android/internal/widget/ViewPager.java
index 6f377b9..93cde3d 100644
--- a/core/java/com/android/internal/widget/ViewPager.java
+++ b/core/java/com/android/internal/widget/ViewPager.java
@@ -353,8 +353,8 @@
         mTouchSlop = configuration.getScaledPagingTouchSlop();
         mMinimumVelocity = (int) (MIN_FLING_VELOCITY * density);
         mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
-        mLeftEdge = new EdgeEffect(context);
-        mRightEdge = new EdgeEffect(context);
+        mLeftEdge = new EdgeEffect(context, attrs);
+        mRightEdge = new EdgeEffect(context, attrs);
 
         mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density);
         mCloseEnough = (int) (CLOSE_ENOUGH * density);
@@ -387,6 +387,28 @@
     }
 
     /**
+     * Returns the {@link EdgeEffect#getType()} for the edge effects.
+     * @return the {@link EdgeEffect#getType()} for the edge effects.
+     * @attr ref android.R.styleable#EdgeEffect_edgeEffectType
+     */
+    @EdgeEffect.EdgeEffectType
+    public int getEdgeEffectType() {
+        // Both left and right edge have the same edge effect type
+        return mLeftEdge.getType();
+    }
+
+    /**
+     * Sets the {@link EdgeEffect#setType(int)} for the edge effects.
+     * @param type The edge effect type to use for the edge effects.
+     * @attr ref android.R.styleable#EdgeEffect_edgeEffectType
+     */
+    public void setEdgeEffectType(@EdgeEffect.EdgeEffectType int type) {
+        mLeftEdge.setType(type);
+        mRightEdge.setType(type);
+        invalidate();
+    }
+
+    /**
      * Set a PagerAdapter that will supply views for this pager as needed.
      *
      * @param adapter Adapter to use
@@ -1891,7 +1913,7 @@
                 }
                 if (mIsBeingDragged) {
                     // Scroll to follow the motion event
-                    if (performDrag(x)) {
+                    if (performDrag(x, y)) {
                         postInvalidateOnAnimation();
                     }
                 }
@@ -1918,6 +1940,17 @@
                     mIsBeingDragged = true;
                     requestParentDisallowInterceptTouchEvent(true);
                     setScrollState(SCROLL_STATE_DRAGGING);
+                } else if (mLeftEdge.getDistance() != 0
+                        || mRightEdge.getDistance() != 0) {
+                    // Caught the edge glow animation
+                    mIsBeingDragged = true;
+                    setScrollState(SCROLL_STATE_DRAGGING);
+                    if (mLeftEdge.getDistance() != 0) {
+                        mLeftEdge.onPullDistance(0f, 1 - mLastMotionY / getHeight());
+                    }
+                    if (mRightEdge.getDistance() != 0) {
+                        mRightEdge.onPullDistance(0f, mLastMotionY / getHeight());
+                    }
                 } else {
                     completeScroll(false);
                     mIsBeingDragged = false;
@@ -2009,7 +2042,7 @@
                     // Scroll to follow the motion event
                     final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
                     final float x = ev.getX(activePointerIndex);
-                    needsInvalidate |= performDrag(x);
+                    needsInvalidate |= performDrag(x, ev.getY(activePointerIndex));
                 }
                 break;
             case MotionEvent.ACTION_UP:
@@ -2080,12 +2113,43 @@
         }
     }
 
-    private boolean performDrag(float x) {
+    /**
+     * If either of the horizontal edge glows are currently active, this consumes part or all of
+     * deltaX on the edge glow.
+     *
+     * @param deltaX The pointer motion, in pixels, in the horizontal direction, positive
+     *                         for moving down and negative for moving up.
+     * @param y The vertical position of the pointer.
+     * @return The amount of <code>deltaX</code> that has been consumed by the
+     * edge glow.
+     */
+    private float releaseHorizontalGlow(float deltaX, float y) {
+        // First allow releasing existing overscroll effect:
+        float consumed = 0;
+        float displacement = y / getHeight();
+        float pullDistance = (float) deltaX / getWidth();
+        if (mLeftEdge.getDistance() != 0) {
+            consumed = -mLeftEdge.onPullDistance(-pullDistance, 1 - displacement);
+        } else if (mRightEdge.getDistance() != 0) {
+            consumed = mRightEdge.onPullDistance(pullDistance, displacement);
+        }
+        return consumed * getWidth();
+    }
+
+    private boolean performDrag(float x, float y) {
         boolean needsInvalidate = false;
 
+        final float dX = mLastMotionX - x;
         final int width = getPaddedWidth();
-        final float deltaX = mLastMotionX - x;
         mLastMotionX = x;
+        final float releaseConsumed = releaseHorizontalGlow(dX, y);
+        final float deltaX = dX - releaseConsumed;
+        if (releaseConsumed != 0) {
+            needsInvalidate = true;
+        }
+        if (Math.abs(deltaX) < 0.0001f) { // ignore rounding errors from releaseHorizontalGlow()
+            return needsInvalidate;
+        }
 
         final EdgeEffect startEdge;
         final EdgeEffect endEdge;
@@ -2128,14 +2192,14 @@
         if (scrollStart < startBound) {
             if (startAbsolute) {
                 final float over = startBound - scrollStart;
-                startEdge.onPull(Math.abs(over) / width);
+                startEdge.onPullDistance(over / width, 1 - y / getHeight());
                 needsInvalidate = true;
             }
             clampedScrollStart = startBound;
         } else if (scrollStart > endBound) {
             if (endAbsolute) {
                 final float over = scrollStart - endBound;
-                endEdge.onPull(Math.abs(over) / width);
+                endEdge.onPullDistance(over / width, y / getHeight());
                 needsInvalidate = true;
             }
             clampedScrollStart = endBound;
@@ -2228,7 +2292,9 @@
      */
     private int determineTargetPage(int currentPage, float pageOffset, int velocity, int deltaX) {
         int targetPage;
-        if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity) {
+        if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity
+                && mLeftEdge.getDistance() == 0 // don't fling while stretched
+                && mRightEdge.getDistance() == 0) {
             targetPage = currentPage - (velocity < 0 ? mLeftIncr : 0);
         } else {
             final float truncator = currentPage >= mCurItem ? 0.4f : 0.6f;
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index a153fab..f49a834 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -149,7 +149,6 @@
                 "android_os_VintfRuntimeInfo.cpp",
                 "android_os_incremental_IncrementalManager.cpp",
                 "android_net_LocalSocketImpl.cpp",
-                "android_net_NetworkUtils.cpp",
                 "android_service_DataLoaderService.cpp",
                 "android_util_AssetManager.cpp",
                 "android_util_Binder.cpp",
@@ -222,6 +221,7 @@
 
             static_libs: [
                 "libasync_safe",
+                "libconnectivityframeworkutils",
                 "libbinderthreadstateutils",
                 "libdmabufinfo",
                 "libgif",
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 62767a6..de5df20 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -1450,6 +1450,42 @@
     track->setPlayerIId(playerIId);
 }
 
+static jint android_media_AudioTrack_getStartThresholdInFrames(JNIEnv *env, jobject thiz) {
+    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+    if (lpTrack == nullptr) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          "Unable to retrieve AudioTrack pointer for getStartThresholdInFrames()");
+        return (jint)AUDIO_JAVA_ERROR;
+    }
+    const ssize_t result = lpTrack->getStartThresholdInFrames();
+    if (result <= 0) {
+        jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+                             "Internal error detected in getStartThresholdInFrames() = %zd",
+                             result);
+        return (jint)AUDIO_JAVA_ERROR;
+    }
+    return (jint)result; // this should be a positive value.
+}
+
+static jint android_media_AudioTrack_setStartThresholdInFrames(JNIEnv *env, jobject thiz,
+                                                               jint startThresholdInFrames) {
+    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+    if (lpTrack == nullptr) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          "Unable to retrieve AudioTrack pointer for setStartThresholdInFrames()");
+        return (jint)AUDIO_JAVA_ERROR;
+    }
+    // non-positive values of startThresholdInFrames are not allowed by the Java layer.
+    const ssize_t result = lpTrack->setStartThresholdInFrames(startThresholdInFrames);
+    if (result <= 0) {
+        jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+                             "Internal error detected in setStartThresholdInFrames() = %zd",
+                             result);
+        return (jint)AUDIO_JAVA_ERROR;
+    }
+    return (jint)result; // this should be a positive value.
+}
+
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 static const JNINativeMethod gMethods[] = {
@@ -1530,6 +1566,10 @@
         {"native_setLogSessionId", "(Ljava/lang/String;)V",
          (void *)android_media_AudioTrack_setLogSessionId},
         {"native_setPlayerIId", "(I)V", (void *)android_media_AudioTrack_setPlayerIId},
+        {"native_setStartThresholdInFrames", "(I)I",
+         (void *)android_media_AudioTrack_setStartThresholdInFrames},
+        {"native_getStartThresholdInFrames", "()I",
+         (void *)android_media_AudioTrack_getStartThresholdInFrames},
 };
 
 // field names found in android/media/AudioTrack.java
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 65b8b98..f54ffc5 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -498,19 +498,14 @@
     transaction->setAnimationTransaction();
 }
 
-static void nativeSetEarlyWakeup(JNIEnv* env, jclass clazz, jlong transactionObj) {
-    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
-    transaction->setEarlyWakeup();
-}
-
 static void nativeSetEarlyWakeupStart(JNIEnv* env, jclass clazz, jlong transactionObj) {
     auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
-    transaction->setExplicitEarlyWakeupStart();
+    transaction->setEarlyWakeupStart();
 }
 
 static void nativeSetEarlyWakeupEnd(JNIEnv* env, jclass clazz, jlong transactionObj) {
     auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
-    transaction->setExplicitEarlyWakeupEnd();
+    transaction->setEarlyWakeupEnd();
 }
 
 static void nativeSetLayer(JNIEnv* env, jclass clazz, jlong transactionObj,
@@ -1737,8 +1732,6 @@
             (void*)nativeMergeTransaction },
     {"nativeSetAnimationTransaction", "(J)V",
             (void*)nativeSetAnimationTransaction },
-    {"nativeSetEarlyWakeup", "(J)V",
-            (void*)nativeSetEarlyWakeup },
     {"nativeSetEarlyWakeupStart", "(J)V",
             (void*)nativeSetEarlyWakeupStart },
     {"nativeSetEarlyWakeupEnd", "(J)V",
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index be17d92..0bed29b 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -825,7 +825,7 @@
   PrepareDir(user_source, 0710, user_id ? AID_ROOT : AID_SHELL,
              multiuser_get_uid(user_id, AID_EVERYBODY), fail_fn);
 
-  bool isAppDataIsolationEnabled = GetBoolProperty(kVoldAppDataIsolation, true);
+  bool isAppDataIsolationEnabled = GetBoolProperty(kVoldAppDataIsolation, false);
 
   if (mount_mode == MOUNT_EXTERNAL_PASS_THROUGH) {
       const std::string pass_through_source = StringPrintf("/mnt/pass_through/%d", user_id);
diff --git a/core/proto/android/net/networkcapabilities.proto b/core/proto/android/net/networkcapabilities.proto
new file mode 100644
index 0000000..edb6c04
--- /dev/null
+++ b/core/proto/android/net/networkcapabilities.proto
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+syntax = "proto2";
+
+package android.net;
+
+option java_multiple_files = true;
+
+import "frameworks/base/core/proto/android/privacy.proto";
+import "frameworks/proto_logging/stats/enums/net/enums.proto";
+
+/**
+ * An android.net.NetworkCapabilities object.
+ */
+message NetworkCapabilitiesProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    repeated Transport transports = 1;
+
+    enum NetCapability {
+        // Indicates this is a network that has the ability to reach the
+        // carrier's MMSC for sending and receiving MMS messages.
+        NET_CAPABILITY_MMS = 0;
+        // Indicates this is a network that has the ability to reach the
+        // carrier's SUPL server, used to retrieve GPS information.
+        NET_CAPABILITY_SUPL = 1;
+        // Indicates this is a network that has the ability to reach the
+        // carrier's DUN or tethering gateway.
+        NET_CAPABILITY_DUN = 2;
+        // Indicates this is a network that has the ability to reach the
+        // carrier's FOTA portal, used for over the air updates.
+        NET_CAPABILITY_FOTA = 3;
+        // Indicates this is a network that has the ability to reach the
+        // carrier's IMS servers, used for network registration and signaling.
+        NET_CAPABILITY_IMS = 4;
+        // Indicates this is a network that has the ability to reach the
+        // carrier's CBS servers, used for carrier specific services.
+        NET_CAPABILITY_CBS = 5;
+        // Indicates this is a network that has the ability to reach a Wi-Fi
+        // direct peer.
+        NET_CAPABILITY_WIFI_P2P = 6;
+        // Indicates this is a network that has the ability to reach a carrier's
+        // Initial Attach servers.
+        NET_CAPABILITY_IA = 7;
+        // Indicates this is a network that has the ability to reach a carrier's
+        // RCS servers, used for Rich Communication Services.
+        NET_CAPABILITY_RCS = 8;
+        // Indicates this is a network that has the ability to reach a carrier's
+        // XCAP servers, used for configuration and control.
+        NET_CAPABILITY_XCAP = 9;
+        // Indicates this is a network that has the ability to reach a carrier's
+        // Emergency IMS servers or other services, used for network signaling
+        // during emergency calls.
+        NET_CAPABILITY_EIMS = 10;
+        // Indicates that this network is unmetered.
+        NET_CAPABILITY_NOT_METERED = 11;
+        // Indicates that this network should be able to reach the internet.
+        NET_CAPABILITY_INTERNET = 12;
+        // Indicates that this network is available for general use. If this is
+        // not set applications should not attempt to communicate on this
+        // network. Note that this is simply informative and not enforcement -
+        // enforcement is handled via other means. Set by default.
+        NET_CAPABILITY_NOT_RESTRICTED = 13;
+        // Indicates that the user has indicated implicit trust of this network.
+        // This generally means it's a sim-selected carrier, a plugged in
+        // ethernet, a paired BT device or a wifi the user asked to connect to.
+        // Untrusted networks are probably limited to unknown wifi AP. Set by
+        // default.
+        NET_CAPABILITY_TRUSTED = 14;
+        // Indicates that this network is not a VPN.  This capability is set by
+        // default and should be explicitly cleared for VPN networks.
+        NET_CAPABILITY_NOT_VPN = 15;
+        // Indicates that connectivity on this network was successfully
+        // validated. For example, for a network with NET_CAPABILITY_INTERNET,
+        // it means that Internet connectivity was successfully detected.
+        NET_CAPABILITY_VALIDATED = 16;
+        // Indicates that this network was found to have a captive portal in
+        // place last time it was probed.
+        NET_CAPABILITY_CAPTIVE_PORTAL = 17;
+        // Indicates that this network is not roaming.
+        NET_CAPABILITY_NOT_ROAMING = 18;
+        // Indicates that this network is available for use by apps, and not a
+        // network that is being kept up in the background to facilitate fast
+        // network switching.
+        NET_CAPABILITY_FOREGROUND = 19;
+    }
+    repeated NetCapability capabilities = 2;
+
+    // Passive link bandwidth. This is a rough guide of the expected peak
+    // bandwidth for the first hop on the given transport.  It is not measured,
+    // but may take into account link parameters (Radio technology, allocated
+    // channels, etc).
+    optional int32 link_up_bandwidth_kbps = 3;
+    optional int32 link_down_bandwidth_kbps = 4;
+
+    optional string network_specifier = 5 [ (.android.privacy).dest = DEST_EXPLICIT ];
+
+    // True if this object specifies a signal strength.
+    optional bool can_report_signal_strength = 6;
+    // This is a signed integer, and higher values indicate better signal. The
+    // exact units are bearer-dependent. For example, Wi-Fi uses RSSI.
+    // Only valid if can_report_signal_strength is true.
+    optional sint32 signal_strength = 7;
+}
diff --git a/core/proto/android/net/networkrequest.proto b/core/proto/android/net/networkrequest.proto
index 0041f19..57b9f71 100644
--- a/core/proto/android/net/networkrequest.proto
+++ b/core/proto/android/net/networkrequest.proto
@@ -20,8 +20,8 @@
 
 option java_multiple_files = true;
 
+import "frameworks/base/core/proto/android/net/networkcapabilities.proto";
 import "frameworks/base/core/proto/android/privacy.proto";
-import "frameworks/proto_logging/stats/enums/net/networkcapabilities.proto";
 
 /**
  * An android.net.NetworkRequest object.
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index a5fbae9..998ec96 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -55,13 +55,13 @@
 import "frameworks/base/core/proto/android/service/procstats.proto";
 import "frameworks/base/core/proto/android/service/restricted_image.proto";
 import "frameworks/base/core/proto/android/service/sensor_service.proto";
+import "frameworks/base/core/proto/android/service/usb.proto";
 import "frameworks/base/core/proto/android/util/event_log_tags.proto";
 import "frameworks/base/core/proto/android/util/log.proto";
 import "frameworks/base/core/proto/android/util/textdump.proto";
 import "frameworks/base/core/proto/android/privacy.proto";
 import "frameworks/base/core/proto/android/section.proto";
 import "frameworks/base/proto/src/ipconnectivity.proto";
-import "frameworks/proto_logging/stats/enums/service/usb.proto";
 import "packages/modules/Permission/service/proto/com/android/role/roleservice.proto";
 
 package android.os;
diff --git a/core/proto/android/server/biometrics.proto b/core/proto/android/server/biometrics.proto
index 900235e..bbb0edd 100644
--- a/core/proto/android/server/biometrics.proto
+++ b/core/proto/android/server/biometrics.proto
@@ -125,6 +125,13 @@
 
     // User states for this sensor.
     repeated UserStateProto user_states = 4;
+
+    // True if resetLockout requires a HAT to be verified in the TEE or equivalent.
+    optional bool reset_lockout_requires_hardware_auth_token = 5;
+
+    // True if a HAT is required (field above) AND a challenge needs to be generated by the
+    // biometric TEE (or equivalent), and wrapped within the HAT.
+    optional bool reset_lockout_requires_challenge = 6;
 }
 
 // State of a specific user for a specific sensor.
diff --git a/core/proto/android/service/enums.proto b/core/proto/android/service/enums.proto
deleted file mode 100644
index b64e685..0000000
--- a/core/proto/android/service/enums.proto
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-syntax = "proto2";
-package android.service;
-
-option java_outer_classname = "ServiceProtoEnums";
-option java_multiple_files = true;
-
-enum UsbEndPointType {
-    USB_ENDPOINT_TYPE_XFER_CONTROL = 0;
-    USB_ENDPOINT_TYPE_XFER_ISOC = 1;
-    USB_ENDPOINT_TYPE_XFER_BULK = 2;
-    USB_ENDPOINT_TYPE_XFER_INT = 3;
-}
-
-enum UsbEndPointDirection {
-    USB_ENDPOINT_DIR_OUT = 0;
-    USB_ENDPOINT_DIR_IN = 0x80;
-}
-
-enum UsbConnectionRecordMode {
-    USB_CONNECTION_RECORD_MODE_CONNECT = 0;
-    USB_CONNECTION_RECORD_MODE_CONNECT_BADPARSE = 1;
-    USB_CONNECTION_RECORD_MODE_CONNECT_BADDEVICE = 2;
-    USB_CONNECTION_RECORD_MODE_DISCONNECT = -1;
-}
\ No newline at end of file
diff --git a/core/proto/android/service/usb.proto b/core/proto/android/service/usb.proto
new file mode 100644
index 0000000..45f8c132
--- /dev/null
+++ b/core/proto/android/service/usb.proto
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+syntax = "proto2";
+package android.service.usb;
+
+option java_multiple_files = true;
+option java_outer_classname = "UsbServiceProto";
+
+import "frameworks/base/core/proto/android/content/component_name.proto";
+import "frameworks/base/core/proto/android/privacy.proto";
+import "frameworks/proto_logging/stats/enums/service/enums.proto";
+
+message UsbServiceDumpProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional UsbDeviceManagerProto device_manager = 1;
+    optional UsbHostManagerProto host_manager = 2;
+    optional UsbPortManagerProto port_manager = 3;
+    optional UsbAlsaManagerProto alsa_manager = 4;
+    optional UsbSettingsManagerProto settings_manager = 5;
+    optional UsbPermissionsManagerProto permissions_manager = 6;
+}
+
+message UsbDeviceManagerProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional UsbHandlerProto handler = 1;
+    optional UsbDebuggingManagerProto debugging_manager = 2;
+}
+
+message UsbHandlerProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    /* Same as android.hardware.usb.gadget.V1_0.GadgetFunction.* */
+    enum Function {
+        FUNCTION_ADB = 1;
+        FUNCTION_ACCESSORY = 2;
+        FUNCTION_MTP = 4;
+        FUNCTION_MIDI = 8;
+        FUNCTION_PTP = 16;
+        FUNCTION_RNDIS = 32;
+        FUNCTION_AUDIO_SOURCE = 64;
+    }
+
+    repeated Function current_functions = 1;
+    optional bool current_functions_applied = 2;
+    repeated Function screen_unlocked_functions = 3;
+    optional bool screen_locked = 4;
+    optional bool connected = 5;
+    optional bool configured = 6;
+    optional UsbAccessoryProto current_accessory = 7;
+    optional bool host_connected = 8;
+    optional bool source_power = 9;
+    optional bool sink_power = 10;
+    optional bool usb_charging = 11;
+    optional bool hide_usb_notification = 12;
+    optional bool audio_accessory_connected = 13;
+    optional bool adb_enabled = 14;
+    optional string kernel_state = 15;
+    optional string kernel_function_list = 16;
+}
+
+message UsbAccessoryProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional string manufacturer = 1;
+    optional string model = 2;
+    // For "classical" USB-accessories the manufacturer bakes this into the
+    // firmware of the device. If an Android phone is configured as accessory, the
+    // app that sets up the accessory side of the connection set this. Either way,
+    // these are part of the detection protocol, and so they cannot be user set or
+    // unique.
+    optional string description = 3;
+    optional string version = 4;
+    optional string uri = 5 [ (android.privacy).dest = DEST_EXPLICIT ];
+    // Non-resettable hardware ID.
+    optional string serial = 6 [ (android.privacy).dest = DEST_LOCAL ];
+}
+
+message UsbDebuggingManagerProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional bool connected_to_adb = 1;
+    // A workstation that connects to the phone for debugging is identified by
+    // this key.
+    optional string last_key_received = 2 [ (android.privacy).dest = DEST_EXPLICIT ];
+    optional string user_keys = 3 [ (android.privacy).dest = DEST_LOCAL ];
+    optional string system_keys = 4 [ (android.privacy).dest = DEST_LOCAL ];
+}
+
+message UsbHostManagerProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional android.content.ComponentNameProto default_usb_host_connection_handler = 1;
+    repeated UsbDeviceProto devices = 2;
+    optional int32 num_connects = 3;
+    repeated UsbConnectionRecordProto connections = 4;
+}
+
+message UsbDeviceProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    // Generic USB name, not user-provided.
+    optional string name = 1;
+    // ID specific to the vendor, not the device.
+    optional int32 vendor_id = 2;
+    // ID of this product type: Each vendor gives each product a unique ID. E.g.
+    // all mice of the same model would have the same ID.
+    optional int32 product_id = 3;
+    optional int32 class = 4;
+    optional int32 subclass = 5;
+    optional int32 protocol = 6;
+    optional string manufacturer_name = 7;
+    optional string product_name = 8;
+    optional string version = 9;
+    // Non-resettable hardware ID.
+    optional string serial_number = 10 [ (android.privacy).dest = DEST_LOCAL ];
+    repeated UsbConfigurationProto configurations = 11;
+}
+
+message UsbConfigurationProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    // A single USB device can have several configurations and the app accessing
+    // the USB device can switch between them. At any time only one can be active.
+    // Each configuration can present completely different interfaces end
+    // endpoints, i.e. a completely different behavior.
+    optional int32 id = 1;
+    // Hardware-defined name, not set by the user.
+    optional string name = 2;
+    optional uint32 attributes = 3;
+    optional int32 max_power = 4;
+    repeated UsbInterfaceProto interfaces = 5;
+}
+
+message UsbInterfaceProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    // Hardware defined. This is the id used by the app to identify the interface.
+    optional int32 id = 1;
+    optional int32 alternate_settings = 2;
+    optional string name = 3;
+    optional int32 class = 4;
+    optional int32 subclass = 5;
+    optional int32 protocol = 6;
+    repeated UsbEndPointProto endpoints = 7;
+}
+
+message UsbEndPointProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional int32 endpoint_number = 1;
+    optional android.service.UsbEndPointDirection direction = 2;
+      // The address of the endpoint. Needed to read and write to the endpoint.
+    optional int32 address = 3;
+    optional android.service.UsbEndPointType type = 4;
+    optional uint32 attributes = 5;
+    optional int32 max_packet_size = 6;
+    optional int32 interval = 7;
+}
+
+message UsbConnectionRecordProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    // usb device's address, e.g. 001/002, nothing about the phone
+    optional string device_address = 1;
+    optional android.service.UsbConnectionRecordMode mode = 2;
+    optional int64 timestamp = 3;
+    optional int32 manufacturer = 4;
+    optional int32 product = 5;
+    optional UsbIsHeadsetProto is_headset = 6;
+}
+
+message UsbIsHeadsetProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional bool in = 1;
+    optional bool out = 2;
+}
+
+message UsbPortManagerProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional bool is_simulation_active = 1;
+    repeated UsbPortInfoProto usb_ports = 2;
+    optional bool enable_usb_data_signaling = 3;
+}
+
+message UsbPortInfoProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional UsbPortProto port = 1;
+    optional UsbPortStatusProto status = 2;
+    optional bool can_change_mode = 3;
+    optional bool can_change_power_role = 4;
+    optional bool can_change_data_role = 5;
+    optional int64 connected_at_millis = 6;
+    optional int64 last_connect_duration_millis = 7;
+}
+
+message UsbPortProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    /* Same as android.hardware.usb.V1_1.Constants.PortMode_1_1 */
+    enum Mode {
+        MODE_NONE = 0;
+        MODE_UFP = 1;
+        MODE_DFP = 2;
+        MODE_DRP = 3;
+        MODE_AUDIO_ACCESSORY = 4;
+        MODE_DEBUG_ACCESSORY = 8;
+    }
+
+    // ID of the port. A device (eg: Chromebooks) might have multiple ports.
+    optional string id = 1;
+    repeated Mode supported_modes = 2;
+}
+
+message UsbPortStatusProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    /* Same as android.hardware.usb.V1_0.Constants.PortPowerRole */
+    enum PowerRole {
+        POWER_ROLE_NONE = 0;
+        POWER_ROLE_SOURCE = 1;
+        POWER_ROLE_SINK = 2;
+    }
+
+    /* Same as android.hardware.usb.V1_0.Constants.PortDataRole */
+    enum DataRole {
+        DATA_ROLE_NONE = 0;
+        DATA_ROLE_HOST = 1;
+        DATA_ROLE_DEVICE = 2;
+    }
+
+    optional bool connected = 1;
+    optional UsbPortProto.Mode current_mode = 2;
+    optional PowerRole power_role = 3;
+    optional DataRole data_role = 4;
+    repeated UsbPortStatusRoleCombinationProto role_combinations = 5;
+    optional android.service.ContaminantPresenceStatus contaminant_presence_status = 6;
+}
+
+message UsbPortStatusRoleCombinationProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional UsbPortStatusProto.PowerRole power_role = 1;
+    optional UsbPortStatusProto.DataRole data_role = 2;
+}
+
+message UsbAlsaManagerProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional int32 cards_parser = 1;
+    repeated UsbAlsaDeviceProto alsa_devices = 2;
+    repeated UsbMidiDeviceProto midi_devices = 3;
+}
+
+message UsbAlsaDeviceProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional int32 card = 1;
+    optional int32 device = 2;
+    optional string name = 3;
+    optional bool has_playback = 4;
+    optional bool has_capture = 5;
+    // usb device's address, e.g. 001/002, nothing about the phone
+    optional string address = 6;
+}
+
+message UsbMidiDeviceProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional int32 card = 1;
+    optional int32 device = 2;
+    // usb device's address, e.g. 001/002, nothing about the phone
+    optional string device_address = 3;
+}
+
+message UsbSettingsManagerProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    repeated UsbUserSettingsManagerProto user_settings = 1;
+    repeated UsbProfileGroupSettingsManagerProto profile_group_settings = 2;
+}
+
+message UsbUserSettingsManagerProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional int32 user_id = 1;
+    reserved 2; // previously device_permissions, now unused
+    reserved 3; // previously accessory_permissions, now unused
+    repeated UsbDeviceAttachedActivities device_attached_activities = 4;
+    repeated UsbAccessoryAttachedActivities accessory_attached_activities = 5;
+}
+
+message UsbProfileGroupSettingsManagerProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    // The user id of the personal profile if the device has a work profile.
+    optional int32 parent_user_id = 1;
+    repeated UsbSettingsDevicePreferenceProto device_preferences = 2;
+    repeated UsbSettingsAccessoryPreferenceProto accessory_preferences = 3;
+}
+
+message UsbSettingsDevicePreferenceProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional UsbDeviceFilterProto filter = 1;
+    optional UserPackageProto user_package = 2;
+}
+
+message UsbPermissionsManagerProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    repeated UsbUserPermissionsManagerProto user_permissions = 1;
+}
+
+message UsbUserPermissionsManagerProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional int32 user_id = 1;
+
+    repeated UsbDevicePermissionProto device_permissions = 2;
+    repeated UsbAccessoryPermissionProto accessory_permissions = 3;
+
+    repeated UsbDevicePersistentPermissionProto device_persistent_permissions = 4;
+    repeated UsbAccessoryPersistentPermissionProto accessory_persistent_permissions = 5;
+}
+
+message UsbDevicePermissionProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    // Name of device set by manufacturer
+    // All devices of the same model have the same name
+    optional string device_name = 1;
+    repeated int32 uids = 2;
+}
+
+message UsbAccessoryPermissionProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    // Description of accessory set by manufacturer
+    // All accessories of the same model have the same description
+    optional string accessory_description = 1;
+    repeated int32 uids = 2;
+}
+
+message UsbDevicePersistentPermissionProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional UsbDeviceFilterProto device_filter = 1;
+    repeated UsbUidPermissionProto permission_values = 2;
+}
+
+message UsbAccessoryPersistentPermissionProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional UsbAccessoryFilterProto accessory_filter = 1;
+    repeated UsbUidPermissionProto permission_values = 2;
+}
+
+message UsbUidPermissionProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional int32 uid = 1;
+    optional bool is_granted = 2;
+}
+
+message UsbDeviceFilterProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    // Mirrors the vendor_id of UsbDeviceProto.
+    optional int32 vendor_id = 1;
+    optional int32 product_id = 2;
+    optional int32 class = 3;
+    optional int32 subclass = 4;
+    optional int32 protocol = 5;
+    optional string manufacturer_name = 6;
+    optional string product_name = 7;
+    optional string serial_number = 8 [ (android.privacy).dest = DEST_EXPLICIT ];
+}
+
+message UserPackageProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional int32 user_id = 1;
+    optional string package_name =2;
+}
+
+message UsbSettingsAccessoryPreferenceProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional UsbAccessoryFilterProto filter = 1;
+    optional UserPackageProto user_package = 2;
+}
+
+message UsbAccessoryFilterProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional string manufacturer = 1;
+    optional string model = 2;
+    optional string version = 3;
+}
+
+message UsbDeviceAttachedActivities {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional android.content.ComponentNameProto activity = 1;
+    repeated UsbDeviceFilterProto filters = 2;
+}
+
+message UsbAccessoryAttachedActivities {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional android.content.ComponentNameProto activity = 1;
+    repeated UsbAccessoryFilterProto filters = 2;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 521d246..45fd96a 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -694,6 +694,7 @@
 
     <!-- Added in S -->
     <protected-broadcast android:name="android.intent.action.REBOOT_READY" />
+    <protected-broadcast android:name="android.app.action.DEVICE_POLICY_CONSTANTS_CHANGED" />
 
     <!-- ====================================================================== -->
     <!--                          RUNTIME PERMISSIONS                           -->
@@ -2309,11 +2310,6 @@
     <permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"
         android:protectionLevel="signature|privileged" />
 
-    <!-- @SystemApi Allows read access to privileged network state in the device config.
-         @hide Used internally. -->
-    <permission android:name="android.permission.READ_NETWORK_DEVICE_CONFIG"
-        android:protectionLevel="signature|privileged" />
-
     <!-- Allows to read device identifiers and use ICC based authentication like EAP-AKA.
          Often required in authentication to access the carrier's server and manage services
          of the subscriber.
@@ -3707,6 +3703,13 @@
     <permission android:name="android.permission.BIND_HOTWORD_DETECTION_SERVICE"
         android:protectionLevel="signature" />
 
+    <!-- @SystemApi Allows an application to manage hotword detection on the device.
+         <p>Protection level: internal|preinstalled
+         @hide This is not a third-party API (intended for OEMs and system apps).
+    -->
+    <permission android:name="android.permission.MANAGE_HOTWORD_DETECTION"
+                android:protectionLevel="internal|preinstalled" />
+
     <!-- Must be required by a {@link android.service.autofill.AutofillService},
          to ensure that only the system can bind to it.
          <p>Protection level: signature
@@ -4821,7 +4824,7 @@
          TODO(159952358): STOPSHIP: This must be updated to the new "internal" protectionLevel
     -->
     <permission android:name="android.permission.DOMAIN_VERIFICATION_AGENT"
-        android:protectionLevel="signature|privileged" />
+        android:protectionLevel="internal|privileged" />
 
     <!-- @SystemApi @hide Must be required by the domain verification agent's intent
          BroadcastReceiver, to ensure that only the system can interact with it.
@@ -5543,6 +5546,10 @@
     <permission android:name="android.permission.ACCESS_LOCUS_ID_USAGE_STATS"
                 android:protectionLevel="signature|appPredictor" />
 
+    <!-- @hide @SystemApi Allows an application to manage app hibernation state. -->
+    <permission android:name="android.permission.MANAGE_APP_HIBERNATION"
+        android:protectionLevel="signature|installer" />
+
     <!-- @hide @TestApi Allows apps to reset the state of {@link com.android.server.am.AppErrors}.
          <p>CTS tests will use UiAutomation.adoptShellPermissionIdentity() to gain access.  -->
     <permission android:name="android.permission.RESET_APP_ERRORS"
diff --git a/core/res/res/drawable/ic_accessibility_24dp.xml b/core/res/res/drawable/ic_accessibility_24dp.xml
new file mode 100644
index 0000000..51e6959
--- /dev/null
+++ b/core/res/res/drawable/ic_accessibility_24dp.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="21dp"
+        android:height="21dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24">
+    <path
+        android:pathData="M20.5,6c-2.61,0.7 -5.67,1 -8.5,1S6.11,6.7 3.5,6L3,8c1.86,0.5 4,0.83 6,
+        1v13h2v-6h2v6h2V9c2,-0.17 4.14,-0.5 6,-1L20.5,6zM12,6c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2s-2,
+        0.9 -2,2S10.9,6 12,6z"
+        android:fillColor="#FF000000"/>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 62278d5..5e95f94 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2194,6 +2194,7 @@
              Note that even if no splashscreen content is set on the theme, the system may still
              show a splash screen using the other attributes on the theme, like the
              {@link android.R.attr#windowBackground}.
+             {@deprecated Use windowSplashscreenAnimatedIcon instead.}
              -->
         <attr name="windowSplashscreenContent" format="reference" />
 
@@ -2279,6 +2280,10 @@
         <!-- Place an drawable image in the bottom of the starting window, it can be used to
              represent the branding of the application. -->
         <attr name="windowSplashScreenBrandingImage" format="reference"/>
+        <!-- Set a background behind the splash screen icon. This is useful if there is not enough
+             contrast between the window background and the icon. Note the shape would also be
+             masking like an icon. -->
+        <attr name="windowSplashScreenIconBackgroundColor" format="color"/>
     </declare-styleable>
 
     <!-- The set of attributes that describe a AlertDialog's theme. -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 601d66e..0318be7 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2063,6 +2063,14 @@
         requested.  If it does support the feature, it will be as if the manifest didn't
         request it at all. -->
         <attr name="requiredNotFeature" format="string" />
+        <!-- Optional: set of flags that should apply to this permission request. -->
+        <attr name="usesPermissionFlags">
+            <!-- Strong assertion by a developer that they will never use this
+                 permission to derive the physical location of the device, even
+                 when the app has been granted the ACCESS_FINE_LOCATION and/or
+                 ACCESS_COARSE_LOCATION permissions. -->
+            <flag name="neverForLocation" value="0x1" />
+        </attr>
     </declare-styleable>
 
     <!-- <code>required-feature</code> and <code>required-not-feature</code> elements inside
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f6fee88..b0327a5 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -59,6 +59,7 @@
         <item><xliff:g id="id">@string/status_bar_mobile</xliff:g></item>
         <item><xliff:g id="id">@string/status_bar_airplane</xliff:g></item>
         <item><xliff:g id="id">@string/status_bar_no_calling</xliff:g></item>
+        <item><xliff:g id="id">@string/status_bar_call_strength</xliff:g></item>
         <item><xliff:g id="id">@string/status_bar_battery</xliff:g></item>
         <item><xliff:g id="id">@string/status_bar_sensors_off</xliff:g></item>
     </string-array>
@@ -96,6 +97,7 @@
     <string translatable="false" name="status_bar_camera">camera</string>
     <string translatable="false" name="status_bar_airplane">airplane</string>
     <string translatable="false" name="status_bar_no_calling">no_calling</string>
+    <string translatable="false" name="status_bar_call_strength">call_strength</string>
     <string translatable="false" name="status_bar_sensors_off">sensors_off</string>
     <string translatable="false" name="status_bar_screen_record">screen_record</string>
 
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 0979ab55..33cc89d 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2816,6 +2816,7 @@
     <public type="attr" name="iconSpaceReserved" id="0x01010561"/>
     <public type="attr" name="defaultFocusHighlightEnabled" id="0x01010562" />
     <public type="attr" name="persistentWhenFeatureAvailable" id="0x01010563"/>
+    <!-- {@deprecated Use windowSplashscreenAnimatedIcon instead } -->
     <public type="attr" name="windowSplashscreenContent" id="0x01010564" />
     <!-- @hide @SystemApi -->
     <public type="attr" name="requiredSystemPropertyName" id="0x01010565" />
@@ -3070,6 +3071,7 @@
     <public name="windowSplashScreenAnimatedIcon"/>
     <public name="windowSplashScreenAnimationDuration"/>
     <public name="windowSplashScreenBrandingImage"/>
+    <public name="windowSplashScreenIconBackgroundColor"/>
     <public name="splashScreenTheme" />
     <public name="maxResizeWidth" />
     <public name="maxResizeHeight" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 054d108..7ea762c 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -743,6 +743,10 @@
          magnification. [CHAR_LIMIT=NONE]-->
     <string name="notification_channel_accessibility_magnification">Magnification</string>
 
+    <!-- Text shown when viewing channel settings for notifications related to accessibility
+         security policy. [CHAR_LIMIT=NONE]-->
+    <string name="notification_channel_accessibility_security_policy">Accessibility security policy</string>
+
     <!-- Label for foreground service notification when one app is running.
     [CHAR LIMIT=NONE BACKUP_MESSAGE_ID=6826789589341671842] -->
     <string name="foreground_service_app_in_background"><xliff:g id="app_name">%1$s</xliff:g> is
@@ -4588,7 +4592,7 @@
     <string name="color_correction_feature_name">Color Correction</string>
 
     <!-- Title of Reduce Brightness feature, shown in the warning dialog about the accessibility shortcut. [CHAR LIMIT=none] -->
-    <string name="reduce_bright_colors_feature_name">Reduce brightness</string>
+    <string name="reduce_bright_colors_feature_name">Extra dim</string>
 
     <!-- Text in toast to alert the user that the accessibility shortcut turned on an accessibility service. [CHAR LIMIT=none] -->
     <string name="accessibility_shortcut_enabling_service">Held volume keys. <xliff:g id="service_name" example="TalkBack">%1$s</xliff:g> turned on.</string>
@@ -5910,4 +5914,9 @@
     <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>
+
+    <!-- Notification title to prompt the user that some accessibility service has view and control access. [CHAR LIMIT=50] -->
+    <string name="view_and_control_notification_title">Check access settings</string>
+    <!-- Notification content to prompt the user that some accessibility service has view and control access. [CHAR LIMIT=none] -->
+    <string name="view_and_control_notification_content"><xliff:g id="service_name" example="TalkBack">%s</xliff:g> can view and control your screen. Tap to review.</string>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ef5191af..cdeb71c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2977,6 +2977,7 @@
   <java-symbol type="string" name="status_bar_clock" />
   <java-symbol type="string" name="status_bar_airplane" />
   <java-symbol type="string" name="status_bar_no_calling" />
+  <java-symbol type="string" name="status_bar_call_strength" />
   <java-symbol type="string" name="status_bar_mobile" />
   <java-symbol type="string" name="status_bar_ethernet" />
   <java-symbol type="string" name="status_bar_vpn" />
@@ -3390,6 +3391,8 @@
   <java-symbol type="drawable" name="ic_accessibility_color_correction" />
   <java-symbol type="drawable" name="ic_accessibility_magnification" />
 
+  <java-symbol type="string" name="reduce_bright_colors_feature_name" />
+
   <!-- com.android.internal.widget.RecyclerView -->
   <java-symbol type="id" name="item_touch_helper_previous_elevation"/>
   <java-symbol type="dimen" name="item_touch_helper_max_drag_scroll_per_frame"/>
@@ -3541,6 +3544,7 @@
   <java-symbol type="string" name="notification_channel_system_changes" />
   <java-symbol type="string" name="notification_channel_do_not_disturb" />
   <java-symbol type="string" name="notification_channel_accessibility_magnification" />
+  <java-symbol type="string" name="notification_channel_accessibility_security_policy" />
   <java-symbol type="string" name="config_defaultAutofillService" />
   <java-symbol type="string" name="config_defaultOnDeviceSpeechRecognitionService" />
   <java-symbol type="string" name="config_defaultTextClassifierPackage" />
@@ -4320,7 +4324,13 @@
   <java-symbol type="bool" name="config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_allowed" />
   <java-symbol type="bool" name="config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_default" />
 
+  <!-- Ids for RemoteViews -->
   <java-symbol type="id" name="remote_views_next_child" />
   <java-symbol type="id" name="remote_views_stable_id" />
   <java-symbol type="id" name="remote_views_override_id" />
+
+  <!-- View and control prompt -->
+  <java-symbol type="drawable" name="ic_accessibility_24dp" />
+  <java-symbol type="string" name="view_and_control_notification_title" />
+  <java-symbol type="string" name="view_and_control_notification_content" />
 </resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 87ae162..bf42da0 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -170,6 +170,7 @@
         <item name="windowSplashScreenBackground">@color/transparent</item>
         <item name="windowSplashScreenAnimatedIcon">@null</item>
         <item name="windowSplashScreenBrandingImage">@null</item>
+        <item name="windowSplashScreenIconBackgroundColor">@color/transparent</item>
         <item name="windowClipToOutline">false</item>
         <item name="windowFrame">@null</item>
         <item name="windowNoTitle">false</item>
diff --git a/core/tests/bluetoothtests/AndroidTest.xml b/core/tests/bluetoothtests/AndroidTest.xml
new file mode 100644
index 0000000..f93c4eb
--- /dev/null
+++ b/core/tests/bluetoothtests/AndroidTest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for Bluetooth test cases">
+    <option name="test-suite-tag" value="apct"/>
+    <option name="test-suite-tag" value="apct-instrumentation"/>
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="BluetoothTests.apk" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct"/>
+    <option name="test-tag" value="BluetoothTests"/>
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.bluetooth.tests" />
+        <option name="hidden-api-checks" value="false"/>
+        <option name="runner" value="android.bluetooth.BluetoothTestRunner"/>
+    </test>
+</configuration>
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java
index 8b3db7e..c287ea9 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java
@@ -16,13 +16,18 @@
 
 package android.bluetooth.le;
 
-import android.bluetooth.le.ScanRecord;
+import android.os.BytesMatcher;
 import android.os.ParcelUuid;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import com.android.internal.util.HexDump;
+
 import junit.framework.TestCase;
 
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
+import java.util.function.Predicate;
 
 /**
  * Unit test cases for {@link ScanRecord}.
@@ -31,6 +36,66 @@
  * 'com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner'
  */
 public class ScanRecordTest extends TestCase {
+    /**
+     * Example raw beacons captured from a Blue Charm BC011
+     */
+    private static final String RECORD_URL = "0201060303AAFE1716AAFE10EE01626C7565636861726D626561636F6E730009168020691E0EFE13551109426C7565436861726D5F313639363835000000";
+    private static final String RECORD_UUID = "0201060303AAFE1716AAFE00EE626C7565636861726D31000000000001000009168020691E0EFE13551109426C7565436861726D5F313639363835000000";
+    private static final String RECORD_TLM = "0201060303AAFE1116AAFE20000BF017000008874803FB93540916802069080EFE13551109426C7565436861726D5F313639363835000000000000000000";
+    private static final String RECORD_IBEACON = "0201061AFF4C000215426C7565436861726D426561636F6E730EFE1355C509168020691E0EFE13551109426C7565436861726D5F31363936383500000000";
+
+    @SmallTest
+    public void testMatchesAnyField_Eddystone_Parser() {
+        final List<String> found = new ArrayList<>();
+        final Predicate<byte[]> matcher = (v) -> {
+            found.add(HexDump.toHexString(v));
+            return false;
+        };
+        ScanRecord.parseFromBytes(HexDump.hexStringToByteArray(RECORD_URL))
+                .matchesAnyField(matcher);
+
+        assertEquals(Arrays.asList(
+                "020106",
+                "0303AAFE",
+                "1716AAFE10EE01626C7565636861726D626561636F6E7300",
+                "09168020691E0EFE1355",
+                "1109426C7565436861726D5F313639363835"), found);
+    }
+
+    @SmallTest
+    public void testMatchesAnyField_Eddystone() {
+        final BytesMatcher matcher = BytesMatcher.decode("⊆0016AAFE/00FFFFFF");
+        assertMatchesAnyField(RECORD_URL, matcher);
+        assertMatchesAnyField(RECORD_UUID, matcher);
+        assertMatchesAnyField(RECORD_TLM, matcher);
+        assertNotMatchesAnyField(RECORD_IBEACON, matcher);
+    }
+
+    @SmallTest
+    public void testMatchesAnyField_iBeacon_Parser() {
+        final List<String> found = new ArrayList<>();
+        final Predicate<byte[]> matcher = (v) -> {
+            found.add(HexDump.toHexString(v));
+            return false;
+        };
+        ScanRecord.parseFromBytes(HexDump.hexStringToByteArray(RECORD_IBEACON))
+                .matchesAnyField(matcher);
+
+        assertEquals(Arrays.asList(
+                "020106",
+                "1AFF4C000215426C7565436861726D426561636F6E730EFE1355C5",
+                "09168020691E0EFE1355",
+                "1109426C7565436861726D5F313639363835"), found);
+    }
+
+    @SmallTest
+    public void testMatchesAnyField_iBeacon() {
+        final BytesMatcher matcher = BytesMatcher.decode("⊆00FF4C0002/00FFFFFFFF");
+        assertNotMatchesAnyField(RECORD_URL, matcher);
+        assertNotMatchesAnyField(RECORD_UUID, matcher);
+        assertNotMatchesAnyField(RECORD_TLM, matcher);
+        assertMatchesAnyField(RECORD_IBEACON, matcher);
+    }
 
     @SmallTest
     public void testParser() {
@@ -70,4 +135,14 @@
         }
 
     }
+
+    private static void assertMatchesAnyField(String record, BytesMatcher matcher) {
+        assertTrue(ScanRecord.parseFromBytes(HexDump.hexStringToByteArray(record))
+                .matchesAnyField(matcher));
+    }
+
+    private static void assertNotMatchesAnyField(String record, BytesMatcher matcher) {
+        assertFalse(ScanRecord.parseFromBytes(HexDump.hexStringToByteArray(record))
+                .matchesAnyField(matcher));
+    }
 }
diff --git a/core/tests/coretests/BstatsTestApp/AndroidManifest.xml b/core/tests/coretests/BstatsTestApp/AndroidManifest.xml
index 1e6bdc6..fcb1e71 100644
--- a/core/tests/coretests/BstatsTestApp/AndroidManifest.xml
+++ b/core/tests/coretests/BstatsTestApp/AndroidManifest.xml
@@ -19,7 +19,7 @@
 
     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
 
-    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="25"/>
+    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="26"/>
 
     <application>
         <activity android:name=".TestActivity"
diff --git a/core/tests/coretests/src/android/app/time/TimeCapabilitiesTest.java b/core/tests/coretests/src/android/app/time/TimeCapabilitiesTest.java
new file mode 100644
index 0000000..85073b0
--- /dev/null
+++ b/core/tests/coretests/src/android/app/time/TimeCapabilitiesTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.time;
+
+
+import static android.app.time.Capabilities.CAPABILITY_NOT_APPLICABLE;
+import static android.app.time.Capabilities.CAPABILITY_NOT_SUPPORTED;
+import static android.app.time.Capabilities.CAPABILITY_POSSESSED;
+import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
+
+import android.os.UserHandle;
+
+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 TimeCapabilitiesTest {
+
+    private static final UserHandle USER_HANDLE = UserHandle.of(332211);
+
+    @Test
+    public void testBuilder() {
+        TimeCapabilities capabilities = new TimeCapabilities.Builder(USER_HANDLE)
+                .setConfigureAutoTimeDetectionEnabledCapability(CAPABILITY_NOT_APPLICABLE)
+                .setSuggestTimeManuallyCapability(CAPABILITY_NOT_SUPPORTED)
+                .build();
+
+        assertThat(capabilities.getConfigureAutoTimeDetectionEnabledCapability())
+                .isEqualTo(CAPABILITY_NOT_APPLICABLE);
+        assertThat(capabilities.getSuggestTimeManuallyCapability())
+                .isEqualTo(CAPABILITY_NOT_SUPPORTED);
+
+        try {
+            new TimeCapabilities.Builder(USER_HANDLE)
+                    .build();
+            fail("Should throw IllegalStateException");
+        } catch (IllegalStateException ignored) {
+            // expected
+        }
+
+        try {
+            new TimeCapabilities.Builder(USER_HANDLE)
+                    .setConfigureAutoTimeDetectionEnabledCapability(CAPABILITY_NOT_APPLICABLE)
+                    .build();
+            fail("Should throw IllegalStateException");
+        } catch (IllegalStateException ignored) {
+            // expected
+        }
+
+        try {
+            new TimeCapabilities.Builder(USER_HANDLE)
+                    .setSuggestTimeManuallyCapability(CAPABILITY_NOT_APPLICABLE)
+                    .build();
+            fail("Should throw IllegalStateException");
+        } catch (IllegalStateException ignored) {
+            // expected
+        }
+    }
+
+    @Test
+    public void userHandle_notIgnoredInEquals() {
+        TimeCapabilities firstUserCapabilities = new TimeCapabilities.Builder(UserHandle.of(1))
+                .setConfigureAutoTimeDetectionEnabledCapability(CAPABILITY_POSSESSED)
+                .setSuggestTimeManuallyCapability(CAPABILITY_POSSESSED)
+                .build();
+
+        TimeCapabilities secondUserCapabilities = new TimeCapabilities.Builder(UserHandle.of(2))
+                .setConfigureAutoTimeDetectionEnabledCapability(CAPABILITY_POSSESSED)
+                .setSuggestTimeManuallyCapability(CAPABILITY_POSSESSED)
+                .build();
+
+        assertThat(firstUserCapabilities).isNotEqualTo(secondUserCapabilities);
+    }
+
+    @Test
+    public void testParcelable() {
+        TimeCapabilities.Builder builder = new TimeCapabilities.Builder(USER_HANDLE)
+                .setConfigureAutoTimeDetectionEnabledCapability(CAPABILITY_NOT_SUPPORTED)
+                .setSuggestTimeManuallyCapability(CAPABILITY_NOT_SUPPORTED);
+
+        assertRoundTripParcelable(builder.build());
+
+        builder.setSuggestTimeManuallyCapability(CAPABILITY_POSSESSED);
+        assertRoundTripParcelable(builder.build());
+
+        builder.setConfigureAutoTimeDetectionEnabledCapability(CAPABILITY_POSSESSED);
+        assertRoundTripParcelable(builder.build());
+    }
+
+}
diff --git a/core/tests/coretests/src/android/app/time/TimeConfigurationTest.java b/core/tests/coretests/src/android/app/time/TimeConfigurationTest.java
new file mode 100644
index 0000000..7c7cd12
--- /dev/null
+++ b/core/tests/coretests/src/android/app/time/TimeConfigurationTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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.time;
+
+import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
+
+import static com.google.common.truth.Truth.assertThat;
+
+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 TimeConfigurationTest {
+
+    @Test
+    public void testBuilder() {
+        TimeConfiguration first = new TimeConfiguration.Builder()
+                .setAutoDetectionEnabled(true)
+                .build();
+
+        assertThat(first.isAutoDetectionEnabled()).isTrue();
+
+        TimeConfiguration copyFromBuilderConfiguration = new TimeConfiguration.Builder(first)
+                .build();
+
+        assertThat(first).isEqualTo(copyFromBuilderConfiguration);
+    }
+
+    @Test
+    public void testParcelable() {
+        TimeConfiguration.Builder builder = new TimeConfiguration.Builder();
+
+        assertRoundTripParcelable(builder.setAutoDetectionEnabled(true).build());
+
+        assertRoundTripParcelable(builder.setAutoDetectionEnabled(false).build());
+    }
+
+}
diff --git a/core/tests/coretests/src/android/app/time/TimeZoneCapabilitiesTest.java b/core/tests/coretests/src/android/app/time/TimeZoneCapabilitiesTest.java
index 01a25b2..dd93997 100644
--- a/core/tests/coretests/src/android/app/time/TimeZoneCapabilitiesTest.java
+++ b/core/tests/coretests/src/android/app/time/TimeZoneCapabilitiesTest.java
@@ -16,8 +16,8 @@
 
 package android.app.time;
 
-import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED;
-import static android.app.time.TimeZoneCapabilities.CAPABILITY_POSSESSED;
+import static android.app.time.Capabilities.CAPABILITY_NOT_ALLOWED;
+import static android.app.time.Capabilities.CAPABILITY_POSSESSED;
 import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
 
 import static org.junit.Assert.assertEquals;
diff --git a/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java
new file mode 100644
index 0000000..dfc9013
--- /dev/null
+++ b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java
@@ -0,0 +1,127 @@
+/*
+ * 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.hardware.display;
+
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.RemoteException;
+
+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.Mockito;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DisplayManagerGlobalTest {
+
+    private static final long ALL_DISPLAY_EVENTS = DisplayManager.EVENT_FLAG_DISPLAY_ADDED
+                    | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
+                    | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED;
+
+    @Mock
+    private IDisplayManager mDisplayManager;
+
+    @Mock
+    private DisplayManager.DisplayListener mListener;
+
+    @Captor
+    private ArgumentCaptor<IDisplayManagerCallback> mCallbackCaptor;
+
+    private Context mContext;
+    private DisplayManagerGlobal mDisplayManagerGlobal;
+    private Handler mHandler;
+
+    @Before
+    public void setUp() throws RemoteException {
+        MockitoAnnotations.initMocks(this);
+        Mockito.when(mDisplayManager.getPreferredWideGamutColorSpaceId()).thenReturn(0);
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        mHandler = mContext.getMainThreadHandler();
+        mDisplayManagerGlobal = new DisplayManagerGlobal(mDisplayManager);
+    }
+
+    @Test
+    public void testDisplayListenerIsCalled_WhenDisplayEventOccurs() throws RemoteException {
+        mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler, ALL_DISPLAY_EVENTS);
+        Mockito.verify(mDisplayManager)
+                .registerCallbackWithEventMask(mCallbackCaptor.capture(), anyLong());
+        IDisplayManagerCallback callback = mCallbackCaptor.getValue();
+
+        int displayId = 1;
+        callback.onDisplayEvent(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
+        waitForHandler();
+        Mockito.verify(mListener).onDisplayAdded(eq(displayId));
+        Mockito.verifyNoMoreInteractions(mListener);
+
+        Mockito.reset(mListener);
+        callback.onDisplayEvent(1, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
+        waitForHandler();
+        Mockito.verify(mListener).onDisplayChanged(eq(displayId));
+        Mockito.verifyNoMoreInteractions(mListener);
+
+        Mockito.reset(mListener);
+        callback.onDisplayEvent(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
+        waitForHandler();
+        Mockito.verify(mListener).onDisplayRemoved(eq(displayId));
+        Mockito.verifyNoMoreInteractions(mListener);
+    }
+
+    @Test
+    public void testDisplayListenerIsNotCalled_WhenClientIsNotSubscribed() throws RemoteException {
+        // First we subscribe to all events in order to test that the subsequent calls to
+        // registerDisplayListener will update the event mask.
+        mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler, ALL_DISPLAY_EVENTS);
+        Mockito.verify(mDisplayManager)
+                .registerCallbackWithEventMask(mCallbackCaptor.capture(), anyLong());
+        IDisplayManagerCallback callback = mCallbackCaptor.getValue();
+
+        int displayId = 1;
+        mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler,
+                ALL_DISPLAY_EVENTS & ~DisplayManager.EVENT_FLAG_DISPLAY_ADDED);
+        callback.onDisplayEvent(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
+        waitForHandler();
+        Mockito.verifyZeroInteractions(mListener);
+
+        mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler,
+                ALL_DISPLAY_EVENTS & ~DisplayManager.EVENT_FLAG_DISPLAY_CHANGED);
+        callback.onDisplayEvent(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
+        waitForHandler();
+        Mockito.verifyZeroInteractions(mListener);
+
+        mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler,
+                ALL_DISPLAY_EVENTS & ~DisplayManager.EVENT_FLAG_DISPLAY_REMOVED);
+        callback.onDisplayEvent(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
+        waitForHandler();
+        Mockito.verifyZeroInteractions(mListener);
+    }
+
+    private void waitForHandler() {
+        mHandler.runWithScissors(() -> { }, 0);
+    }
+}
diff --git a/core/tests/coretests/src/android/os/BytesMatcherTest.java b/core/tests/coretests/src/android/os/BytesMatcherTest.java
index 67c1b3c9..b28e309 100644
--- a/core/tests/coretests/src/android/os/BytesMatcherTest.java
+++ b/core/tests/coretests/src/android/os/BytesMatcherTest.java
@@ -59,6 +59,19 @@
     }
 
     @Test
+    public void testPrefix() throws Exception {
+        BytesMatcher matcher = BytesMatcher.decode("⊆cafe,⊆beef/ff00");
+        assertTrue(matcher.test(hexStringToByteArray("cafe")));
+        assertFalse(matcher.test(hexStringToByteArray("caff")));
+        assertTrue(matcher.test(hexStringToByteArray("cafecafe")));
+        assertFalse(matcher.test(hexStringToByteArray("ca")));
+        assertTrue(matcher.test(hexStringToByteArray("beef")));
+        assertTrue(matcher.test(hexStringToByteArray("beff")));
+        assertTrue(matcher.test(hexStringToByteArray("beffbeff")));
+        assertFalse(matcher.test(hexStringToByteArray("be")));
+    }
+
+    @Test
     public void testMacAddress() throws Exception {
         BytesMatcher matcher = BytesMatcher.decode("+cafe00112233/ffffff000000");
         assertTrue(matcher.testMacAddress(
@@ -94,13 +107,23 @@
     }
 
     @Test
-    public void testSerialize() throws Exception {
+    public void testSerialize_Empty() throws Exception {
         BytesMatcher matcher = new BytesMatcher();
-        matcher.addRejectRule(hexStringToByteArray("cafe00112233"),
+        matcher = BytesMatcher.decode(BytesMatcher.encode(matcher));
+
+        // Also very empty and null values
+        BytesMatcher.decode("");
+        BytesMatcher.decode(null);
+    }
+
+    @Test
+    public void testSerialize_Exact() throws Exception {
+        BytesMatcher matcher = new BytesMatcher();
+        matcher.addExactRejectRule(hexStringToByteArray("cafe00112233"),
                 hexStringToByteArray("ffffff000000"));
-        matcher.addRejectRule(hexStringToByteArray("beef00112233"),
+        matcher.addExactRejectRule(hexStringToByteArray("beef00112233"),
                 null);
-        matcher.addAcceptRule(hexStringToByteArray("000000000000"),
+        matcher.addExactAcceptRule(hexStringToByteArray("000000000000"),
                 hexStringToByteArray("000000000000"));
 
         assertFalse(matcher.test(hexStringToByteArray("cafe00ffffff")));
@@ -116,6 +139,28 @@
     }
 
     @Test
+    public void testSerialize_Prefix() throws Exception {
+        BytesMatcher matcher = new BytesMatcher();
+        matcher.addExactRejectRule(hexStringToByteArray("aa"), null);
+        matcher.addExactAcceptRule(hexStringToByteArray("bb"), null);
+        matcher.addPrefixAcceptRule(hexStringToByteArray("aa"), null);
+        matcher.addPrefixRejectRule(hexStringToByteArray("bb"), null);
+
+        assertFalse(matcher.test(hexStringToByteArray("aa")));
+        assertTrue(matcher.test(hexStringToByteArray("bb")));
+        assertTrue(matcher.test(hexStringToByteArray("aaaa")));
+        assertFalse(matcher.test(hexStringToByteArray("bbbb")));
+
+        // Bounce through serialization pass and confirm it still works
+        matcher = BytesMatcher.decode(BytesMatcher.encode(matcher));
+
+        assertFalse(matcher.test(hexStringToByteArray("aa")));
+        assertTrue(matcher.test(hexStringToByteArray("bb")));
+        assertTrue(matcher.test(hexStringToByteArray("aaaa")));
+        assertFalse(matcher.test(hexStringToByteArray("bbbb")));
+    }
+
+    @Test
     public void testOrdering_RejectFirst() throws Exception {
         BytesMatcher matcher = BytesMatcher.decode("-ff/0f,+ff/f0");
         assertFalse(matcher.test(hexStringToByteArray("ff")));
diff --git a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
index 7a2e6b7..5de55d7 100644
--- a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
@@ -91,7 +91,8 @@
 
     @Test
     public void testImeVisibility() {
-        final InsetsSourceControl ime = new InsetsSourceControl(ITYPE_IME, mLeash, new Point());
+        final InsetsSourceControl ime =
+                new InsetsSourceControl(ITYPE_IME, mLeash, new Point(), Insets.NONE);
         mController.onControlsChanged(new InsetsSourceControl[] { ime });
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
@@ -119,7 +120,8 @@
             mImeConsumer.applyImeVisibility(true /* setVisible */);
 
             // set control and verify visibility is applied.
-            InsetsSourceControl control = new InsetsSourceControl(ITYPE_IME, mLeash, new Point());
+            InsetsSourceControl control =
+                    new InsetsSourceControl(ITYPE_IME, mLeash, new Point(), Insets.NONE);
             mController.onControlsChanged(new InsetsSourceControl[] { control });
             // IME show animation should be triggered when control becomes available.
             verify(mController).applyAnimation(
@@ -138,7 +140,7 @@
 
             // set control and verify visibility is applied.
             InsetsSourceControl control = Mockito.spy(
-                    new InsetsSourceControl(ITYPE_IME, mLeash, new Point()));
+                    new InsetsSourceControl(ITYPE_IME, mLeash, new Point(), Insets.NONE));
             // Simulate IME source control set this flag when the target has starting window.
             control.setSkipAnimationOnce(true);
             mController.onControlsChanged(new InsetsSourceControl[] { control });
diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
index 873627e..613232f 100644
--- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
+++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
@@ -94,13 +94,14 @@
         InsetsSourceConsumer topConsumer = new InsetsSourceConsumer(ITYPE_STATUS_BAR, mInsetsState,
                 () -> mMockTransaction, mMockController);
         topConsumer.setControl(
-                new InsetsSourceControl(ITYPE_STATUS_BAR, mTopLeash, new Point(0, 0)),
+                new InsetsSourceControl(
+                        ITYPE_STATUS_BAR, mTopLeash, new Point(0, 0), Insets.of(0, 100, 0, 0)),
                 new int[1], new int[1]);
 
         InsetsSourceConsumer navConsumer = new InsetsSourceConsumer(ITYPE_NAVIGATION_BAR,
                 mInsetsState, () -> mMockTransaction, mMockController);
         navConsumer.setControl(new InsetsSourceControl(ITYPE_NAVIGATION_BAR, mNavLeash,
-                new Point(400, 0)), new int[1], new int[1]);
+                new Point(400, 0), Insets.of(0, 0, 100, 0)), new int[1], new int[1]);
         navConsumer.hide();
 
         SparseArray<InsetsSourceControl> controls = new SparseArray<>();
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 2770ed8..ff505c4 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -213,7 +213,8 @@
         mController.onFrameChanged(new Rect(0, 0, 100, 100));
         mController.getState().setDisplayFrame(new Rect(0, 0, 200, 200));
         InsetsSourceControl control =
-                new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point());
+                new InsetsSourceControl(
+                        ITYPE_STATUS_BAR, mLeash, new Point(), Insets.of(0, 10, 0, 0));
         mController.onControlsChanged(new InsetsSourceControl[] { control });
         WindowInsetsAnimationControlListener controlListener =
                 mock(WindowInsetsAnimationControlListener.class);
@@ -814,7 +815,7 @@
         // Simulate binder behavior by copying SurfaceControl. Otherwise, InsetsController will
         // attempt to release mLeash directly.
         SurfaceControl copy = new SurfaceControl(mLeash, "InsetsControllerTest.createControl");
-        return new InsetsSourceControl(type, copy, new Point());
+        return new InsetsSourceControl(type, copy, new Point(), Insets.NONE);
     }
 
     private InsetsSourceControl[] createSingletonControl(@InternalInsetsType int type) {
diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
index 7efd616..b3aa7e8 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
@@ -34,6 +34,7 @@
 
 import android.app.Instrumentation;
 import android.content.Context;
+import android.graphics.Insets;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
@@ -108,7 +109,8 @@
         });
         instrumentation.waitForIdleSync();
 
-        mConsumer.setControl(new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point()),
+        mConsumer.setControl(
+                new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point(), Insets.NONE),
                 new int[1], new int[1]);
     }
 
@@ -177,7 +179,8 @@
             mConsumer.hide();
             verifyZeroInteractions(mMockTransaction);
             int[] hideTypes = new int[1];
-            mConsumer.setControl(new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point()),
+            mConsumer.setControl(
+                    new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point(), Insets.NONE),
                     new int[1], hideTypes);
             assertEquals(statusBars(), hideTypes[0]);
             assertFalse(mRemoveSurfaceCalled);
@@ -194,7 +197,8 @@
             verifyZeroInteractions(mMockTransaction);
             mRemoveSurfaceCalled = false;
             int[] hideTypes = new int[1];
-            mConsumer.setControl(new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point()),
+            mConsumer.setControl(
+                    new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point(), Insets.NONE),
                     new int[1], hideTypes);
             assertTrue(mRemoveSurfaceCalled);
             assertEquals(0, hideTypes[0]);
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 4319740..623e77e 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
@@ -29,6 +29,8 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -74,10 +76,9 @@
  *
  * or
  *
- * bit FrameworksCoreTests:com.android.internal.os.BatteryStatsCpuTimesTest
+ * atest FrameworksCoreTests:com.android.internal.os.BatteryStatsCpuTimesTest
  */
 @SmallTest
-@SkipPresubmit("b/180015146")
 @RunWith(AndroidJUnit4.class)
 public class BatteryStatsCpuTimesTest {
     @Mock
@@ -89,6 +90,8 @@
     @Mock
     KernelCpuUidClusterTimeReader mCpuUidClusterTimeReader;
     @Mock
+    SystemServerCpuThreadReader mSystemServerCpuThreadReader;
+    @Mock
     BatteryStatsImpl.UserInfoProvider mUserInfoProvider;
     @Mock
     PowerProfile mPowerProfile;
@@ -107,6 +110,7 @@
                 .setKernelCpuUidFreqTimeReader(mCpuUidFreqTimeReader)
                 .setKernelCpuUidActiveTimeReader(mCpuUidActiveTimeReader)
                 .setKernelCpuUidClusterTimeReader(mCpuUidClusterTimeReader)
+                .setSystemServerCpuThreadReader(mSystemServerCpuThreadReader)
                 .setUserInfoProvider(mUserInfoProvider);
     }
 
@@ -125,8 +129,8 @@
 
         // VERIFY
         assertArrayEquals("Unexpected cpu freqs", freqs, mBatteryStatsImpl.getCpuFreqs());
-        verify(mCpuUidUserSysTimeReader).readDelta(null);
-        verify(mCpuUidFreqTimeReader).readDelta(null);
+        verify(mCpuUidUserSysTimeReader).readDelta(anyBoolean(), isNull());
+        verify(mCpuUidFreqTimeReader).readDelta(anyBoolean(), isNull());
         for (int i = 0; i < numClusters; ++i) {
             verify(mKernelCpuSpeedReaders[i]).readDelta();
         }
@@ -145,16 +149,16 @@
 
         // VERIFY
         verify(mUserInfoProvider).refreshUserIds();
-        verify(mCpuUidUserSysTimeReader).readDelta(
+        verify(mCpuUidUserSysTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidUserSysTimeReader.Callback.class));
         // perClusterTimesAvailable is called twice, once in updateCpuTimeLocked() and the other
         // in readKernelUidCpuFreqTimesLocked.
         verify(mCpuUidFreqTimeReader, times(2)).perClusterTimesAvailable();
-        verify(mCpuUidFreqTimeReader).readDelta(
+        verify(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidFreqTimeReader.Callback.class));
-        verify(mCpuUidActiveTimeReader).readDelta(
+        verify(mCpuUidActiveTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidActiveTimeReader.Callback.class));
-        verify(mCpuUidClusterTimeReader).readDelta(
+        verify(mCpuUidClusterTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidClusterTimeReader.Callback.class));
         verifyNoMoreInteractions(mCpuUidFreqTimeReader);
         for (int i = 0; i < numClusters; ++i) {
@@ -256,16 +260,16 @@
                 FIRST_APPLICATION_UID + 33
         });
         final long[][] uidTimesUs = {
-                {12, 34}, {34897394, 3123983}, {79775429834l, 8430434903489l}
+                {12, 34}, {34897394, 3123983}, {79775429834L, 8430434903489L}
         };
         doAnswer(invocation -> {
             final KernelCpuUidUserSysTimeReader.Callback<long[]> callback =
-                    (KernelCpuUidUserSysTimeReader.Callback<long[]>) invocation.getArguments()[0];
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], uidTimesUs[i]);
             }
             return null;
-        }).when(mCpuUidUserSysTimeReader).readDelta(
+        }).when(mCpuUidUserSysTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidUserSysTimeReader.Callback.class));
 
         // RUN
@@ -291,16 +295,16 @@
 
         // PRECONDITIONS
         final long[][] deltasUs = {
-                {9379, 3332409833484l}, {493247, 723234}, {3247819, 123348}
+                {9379, 3332409833484L}, {493247, 723234}, {3247819, 123348}
         };
         doAnswer(invocation -> {
             final KernelCpuUidUserSysTimeReader.Callback<long[]> callback =
-                    (KernelCpuUidUserSysTimeReader.Callback<long[]>) invocation.getArguments()[0];
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], deltasUs[i]);
             }
             return null;
-        }).when(mCpuUidUserSysTimeReader).readDelta(
+        }).when(mCpuUidUserSysTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidUserSysTimeReader.Callback.class));
 
         // RUN
@@ -331,16 +335,16 @@
                 FIRST_APPLICATION_UID + 33
         });
         final long[][] uidTimesUs = {
-                {12, 34}, {34897394, 3123983}, {79775429834l, 8430434903489l}
+                {12, 34}, {34897394, 3123983}, {79775429834L, 8430434903489L}
         };
         doAnswer(invocation -> {
             final KernelCpuUidUserSysTimeReader.Callback<long[]> callback =
-                    (KernelCpuUidUserSysTimeReader.Callback<long[]>) invocation.getArguments()[0];
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], uidTimesUs[i]);
             }
             return null;
-        }).when(mCpuUidUserSysTimeReader).readDelta(
+        }).when(mCpuUidUserSysTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidUserSysTimeReader.Callback.class));
 
         // RUN
@@ -367,16 +371,16 @@
         final int ownerUid = UserHandle.getUid(testUserId, FIRST_APPLICATION_UID + 42);
         mBatteryStatsImpl.addIsolatedUidLocked(isolatedUid, ownerUid);
         final long[][] deltasUs = {
-                {9379, 3332409833484l}, {493247, 723234}, {3247819, 123348}
+                {9379, 3332409833484L}, {493247, 723234}, {3247819, 123348}
         };
         doAnswer(invocation -> {
             final KernelCpuUidUserSysTimeReader.Callback<long[]> callback =
-                    (KernelCpuUidUserSysTimeReader.Callback<long[]>) invocation.getArguments()[0];
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], deltasUs[i]);
             }
             return null;
-        }).when(mCpuUidUserSysTimeReader).readDelta(
+        }).when(mCpuUidUserSysTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidUserSysTimeReader.Callback.class));
 
         // RUN
@@ -421,18 +425,18 @@
                 FIRST_APPLICATION_UID + 33
         });
         final long[][] uidTimesUs = {
-                {12, 34}, {34897394, 3123983}, {79775429834l, 8430434903489l}
+                {12, 34}, {34897394, 3123983}, {79775429834L, 8430434903489L}
         };
         doAnswer(invocation -> {
             final KernelCpuUidUserSysTimeReader.Callback<long[]> callback =
-                    (KernelCpuUidUserSysTimeReader.Callback<long[]>) invocation.getArguments()[0];
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], uidTimesUs[i]);
             }
             // And one for the invalid uid
             callback.onUidCpuTime(invalidUid, new long[]{3879, 239});
             return null;
-        }).when(mCpuUidUserSysTimeReader).readDelta(
+        }).when(mCpuUidUserSysTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidUserSysTimeReader.Callback.class));
 
         // RUN
@@ -474,12 +478,12 @@
         };
         doAnswer(invocation -> {
             final KernelCpuUidUserSysTimeReader.Callback<long[]> callback =
-                    (KernelCpuUidUserSysTimeReader.Callback<long[]>) invocation.getArguments()[0];
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], uidTimesUs[i]);
             }
             return null;
-        }).when(mCpuUidUserSysTimeReader).readDelta(
+        }).when(mCpuUidUserSysTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidUserSysTimeReader.Callback.class));
 
         // RUN
@@ -553,13 +557,13 @@
                 {8, 25, 3, 0, 42}
         };
         doAnswer(invocation -> {
-            final KernelCpuUidFreqTimeReader.Callback callback =
-                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             return null;
-        }).when(mCpuUidFreqTimeReader).readDelta(
+        }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
@@ -582,17 +586,17 @@
         updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
         final long[][] deltasMs = {
                 {3, 12, 55, 100, 32},
-                {3248327490475l, 232349349845043l, 123, 2398, 0},
+                {3248327490475L, 232349349845043L, 123, 2398, 0},
                 {43, 3345, 2143, 123, 4554}
         };
         doAnswer(invocation -> {
-            final KernelCpuUidFreqTimeReader.Callback callback =
-                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], deltasMs[i]);
             }
             return null;
-        }).when(mCpuUidFreqTimeReader).readDelta(
+        }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
@@ -636,13 +640,13 @@
                 {8, 25, 3, 0, 42}
         };
         doAnswer(invocation -> {
-            final KernelCpuUidFreqTimeReader.Callback callback =
-                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             return null;
-        }).when(mCpuUidFreqTimeReader).readDelta(
+        }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidFreqTimeReader.Callback.class));
         when(mCpuUidFreqTimeReader.perClusterTimesAvailable()).thenReturn(true);
 
@@ -676,17 +680,17 @@
         updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
         final long[][] deltasMs = {
                 {3, 12, 55, 100, 32},
-                {3248327490475l, 232349349845043l, 123, 2398, 0},
+                {3248327490475L, 232349349845043L, 123, 2398, 0},
                 {43, 3345, 2143, 123, 4554}
         };
         doAnswer(invocation -> {
-            final KernelCpuUidFreqTimeReader.Callback callback =
-                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], deltasMs[i]);
             }
             return null;
-        }).when(mCpuUidFreqTimeReader).readDelta(
+        }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
@@ -746,13 +750,13 @@
                 {8, 25, 3, 0, 42}
         };
         doAnswer(invocation -> {
-            final KernelCpuUidFreqTimeReader.Callback callback =
-                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             return null;
-        }).when(mCpuUidFreqTimeReader).readDelta(
+        }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidFreqTimeReader.Callback.class));
         when(mCpuUidFreqTimeReader.perClusterTimesAvailable()).thenReturn(true);
 
@@ -836,13 +840,13 @@
                 {8, 25, 3, 0, 42}
         };
         doAnswer(invocation -> {
-            final KernelCpuUidFreqTimeReader.Callback callback =
-                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             return null;
-        }).when(mCpuUidFreqTimeReader).readDelta(
+        }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
@@ -865,17 +869,17 @@
         updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
         final long[][] deltasMs = {
                 {3, 12, 55, 100, 32, 34984, 27983},
-                {3248327490475l, 232349349845043l, 123, 2398, 0, 398, 0},
-                {43, 3345, 2143, 123, 4554, 9374983794839l, 979875}
+                {3248327490475L, 232349349845043L, 123, 2398, 0, 398, 0},
+                {43, 3345, 2143, 123, 4554, 9374983794839L, 979875}
         };
         doAnswer(invocation -> {
-            final KernelCpuUidFreqTimeReader.Callback callback =
-                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], deltasMs[i]);
             }
             return null;
-        }).when(mCpuUidFreqTimeReader).readDelta(
+        }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
@@ -913,13 +917,13 @@
                 {8, 25, 3, 0, 42}
         };
         doAnswer(invocation -> {
-            final KernelCpuUidFreqTimeReader.Callback callback =
-                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             return null;
-        }).when(mCpuUidFreqTimeReader).readDelta(
+        }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
@@ -953,13 +957,13 @@
                 {43, 3345, 2143, 123, 4554}
         };
         doAnswer(invocation -> {
-            final KernelCpuUidFreqTimeReader.Callback callback =
-                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], deltasMs[i]);
             }
             return null;
-        }).when(mCpuUidFreqTimeReader).readDelta(
+        }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
@@ -1008,15 +1012,15 @@
                 {8, 25, 3, 0, 42}
         };
         doAnswer(invocation -> {
-            final KernelCpuUidFreqTimeReader.Callback callback =
-                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback<long[]> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             // And one for the invalid uid
             callback.onUidCpuTime(invalidUid, new long[]{12, 839, 32, 34, 21});
             return null;
-        }).when(mCpuUidFreqTimeReader).readDelta(
+        }).when(mCpuUidFreqTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
@@ -1051,13 +1055,13 @@
         });
         final long[] uidTimesMs = {8000, 25000, 3000, 0, 42000};
         doAnswer(invocation -> {
-            final KernelCpuUidActiveTimeReader.Callback callback =
-                    (KernelCpuUidActiveTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidActiveTimeReader.Callback<Long> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             return null;
-        }).when(mCpuUidActiveTimeReader).readDelta(
+        }).when(mCpuUidActiveTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidActiveTimeReader.Callback.class));
 
         // RUN
@@ -1077,13 +1081,13 @@
         updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
         final long[] deltasMs = {43000, 3345000, 2143000, 123000, 4554000};
         doAnswer(invocation -> {
-            final KernelCpuUidActiveTimeReader.Callback callback =
-                    (KernelCpuUidActiveTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidActiveTimeReader.Callback<Long> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], deltasMs[i]);
             }
             return null;
-        }).when(mCpuUidActiveTimeReader).readDelta(
+        }).when(mCpuUidActiveTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidActiveTimeReader.Callback.class));
 
         // RUN
@@ -1115,15 +1119,15 @@
         });
         final long[] uidTimesMs = {8000, 25000, 3000, 0, 42000};
         doAnswer(invocation -> {
-            final KernelCpuUidActiveTimeReader.Callback callback =
-                    (KernelCpuUidActiveTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidActiveTimeReader.Callback<Long> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             // And one for the invalid uid
             callback.onUidCpuTime(invalidUid, 1200L);
             return null;
-        }).when(mCpuUidActiveTimeReader).readDelta(
+        }).when(mCpuUidActiveTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidActiveTimeReader.Callback.class));
 
         // RUN
@@ -1159,13 +1163,13 @@
                 {8000, 0}
         };
         doAnswer(invocation -> {
-            final KernelCpuUidClusterTimeReader.Callback callback =
-                    (KernelCpuUidClusterTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidClusterTimeReader.Callback<long[]> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             return null;
-        }).when(mCpuUidClusterTimeReader).readDelta(
+        }).when(mCpuUidClusterTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidClusterTimeReader.Callback.class));
 
         // RUN
@@ -1189,13 +1193,13 @@
                 {43000, 3345000}
         };
         doAnswer(invocation -> {
-            final KernelCpuUidClusterTimeReader.Callback callback =
-                    (KernelCpuUidClusterTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidClusterTimeReader.Callback<long[]> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], deltasMs[i]);
             }
             return null;
-        }).when(mCpuUidClusterTimeReader).readDelta(
+        }).when(mCpuUidClusterTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidClusterTimeReader.Callback.class));
 
         // RUN
@@ -1232,15 +1236,15 @@
                 {8000, 0}
         };
         doAnswer(invocation -> {
-            final KernelCpuUidClusterTimeReader.Callback callback =
-                    (KernelCpuUidClusterTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidClusterTimeReader.Callback<long[]> callback =
+                    invocation.getArgument(1);
             for (int i = 0; i < testUids.length; ++i) {
                 callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             // And one for the invalid uid
             callback.onUidCpuTime(invalidUid, new long[]{400, 1000});
             return null;
-        }).when(mCpuUidClusterTimeReader).readDelta(
+        }).when(mCpuUidClusterTimeReader).readDelta(anyBoolean(),
                 any(KernelCpuUidClusterTimeReader.Callback.class));
 
         // RUN
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 4fe7d70..13d529c 100644
--- a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
@@ -124,6 +124,7 @@
         sContext.getPackageManager().setApplicationEnabledSetting(TEST_PKG,
                 PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
         sTestPkgUid = sContext.getPackageManager().getPackageUid(TEST_PKG, 0);
+        executeCmd("cmd deviceidle whitelist +" + TEST_PKG);
 
         final ArrayMap<String, String> desiredConstants = new ArrayMap<>();
         desiredConstants.put(KEY_TRACK_CPU_TIMES_BY_PROC_STATE, Boolean.toString(true));
@@ -134,6 +135,7 @@
 
     @AfterClass
     public static void tearDownOnce() throws Exception {
+        executeCmd("cmd deviceidle whitelist -" + TEST_PKG);
         if (sBatteryStatsConstsUpdated) {
             Settings.Global.putString(sContext.getContentResolver(),
                     Settings.Global.BATTERY_STATS_CONSTANTS, sOriginalBatteryStatsConsts);
@@ -382,7 +384,7 @@
     }
 
     @Test
-    @SkipPresubmit("b/180015146 flakey")
+    @SkipPresubmit("b/183225190 flaky")
     public void testCpuFreqTimes_stateFgService() throws Exception {
         if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) {
             Log.w(TAG, "Skipping " + testName.getMethodName()
@@ -515,7 +517,6 @@
     }
 
     @Test
-    @SkipPresubmit("b/180015146")
     public void testCpuFreqTimes_trackingDisabled() throws Exception {
         if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) {
             Log.w(TAG, "Skipping " + testName.getMethodName()
@@ -625,7 +626,7 @@
         splitter.setString(settingsDump);
         String next;
         while (splitter.hasNext()) {
-            next = splitter.next();
+            next = splitter.next().trim();
             if (next.startsWith(key)) {
                 return next.split("=")[1];
             }
diff --git a/data/etc/car/Android.bp b/data/etc/car/Android.bp
index 0268953..8991a61 100644
--- a/data/etc/car/Android.bp
+++ b/data/etc/car/Android.bp
@@ -24,6 +24,14 @@
 }
 
 prebuilt_etc {
+    name: "allowed_privapp_com.android.carsystemui",
+    system_ext_specific: true,
+    sub_dir: "permissions",
+    src: "com.android.carsystemui.xml",
+    filename_from_src: true,
+}
+
+prebuilt_etc {
     name: "allowed_privapp_android.car.cluster.loggingrenderer",
     sub_dir: "permissions",
     src: "android.car.cluster.loggingrenderer.xml",
diff --git a/data/etc/car/com.android.car.messenger.xml b/data/etc/car/com.android.car.messenger.xml
index 16595c3..9e5f339 100644
--- a/data/etc/car/com.android.car.messenger.xml
+++ b/data/etc/car/com.android.car.messenger.xml
@@ -16,6 +16,7 @@
   -->
 <permissions>
     <privapp-permissions package="com.android.car.messenger">
+        <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
         <permission name="android.car.permission.ACCESS_CAR_PROJECTION_STATUS"/>
     </privapp-permissions>
 </permissions>
diff --git a/data/etc/car/com.android.carsystemui.xml b/data/etc/car/com.android.carsystemui.xml
new file mode 100644
index 0000000..4e2f294
--- /dev/null
+++ b/data/etc/car/com.android.carsystemui.xml
@@ -0,0 +1,25 @@
+<?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
+  -->
+<permissions>
+    <privapp-permissions package="com.android.systemui">
+        <permission name="android.car.permission.ACCESS_CAR_PROJECTION_STATUS"/>
+        <permission name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME"/>
+        <permission name="android.car.permission.CAR_ENROLL_TRUST"/>
+        <permission name="android.car.permission.CAR_POWER"/>
+        <permission name="android.car.permission.CONTROL_CAR_CLIMATE"/>
+    </privapp-permissions>
+</permissions>
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index b171599..27bf4ef 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -60,10 +60,6 @@
         <group gid="log" />
     </permission>
 
-    <permission name="android.permission.MANAGE_EXTERNAL_STORAGE" >
-        <group gid="external_storage" />
-    </permission>
-
     <permission name="android.permission.ACCESS_MTP" >
         <group gid="mtp" />
     </permission>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index a7b6636..1924e5f 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -490,6 +490,11 @@
         <permission name="android.permission.SET_CLIP_SOURCE" />
         <!-- Permission required for CTS test - FontManagerTest -->
         <permission name="android.permission.UPDATE_FONTS" />
+        <!-- Permission required for hotword detection service CTS tests -->
+        <permission name="android.permission.MANAGE_HOTWORD_DETECTION" />
+        <permission name="android.permission.MANAGE_APP_HIBERNATION"/>
+        <!-- Permission required for CTS test - ResourceObserverNativeTest -->
+        <permission name="android.permission.REGISTER_MEDIA_RESOURCE_OBSERVER" />
     </privapp-permissions>
 
     <privapp-permissions package="com.android.statementservice">
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 115bd9b..c70d6b0 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -1231,6 +1231,12 @@
       "group": "WM_DEBUG_TASKS",
       "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
     },
+    "-672355406": {
+      "message": "  Rejecting as no-op: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
     "-672228342": {
       "message": "resumeTopActivityLocked: Top activity resumed %s",
       "level": "DEBUG",
@@ -3307,6 +3313,12 @@
       "group": "WM_DEBUG_WINDOW_TRANSITIONS",
       "at": "com\/android\/server\/wm\/TransitionController.java"
     },
+    "1804245629": {
+      "message": "Attempted to add starting window to token but already cleaned",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
     "1810019902": {
       "message": "TRANSIT_FLAG_OPEN_BEHIND,  adding %s to mOpeningApps",
       "level": "DEBUG",
@@ -3433,6 +3445,12 @@
       "group": "WM_DEBUG_IME",
       "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
     },
+    "1931178855": {
+      "message": "\tnonApp=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
     "1947239194": {
       "message": "Deferring rotation, still finishing previous rotation",
       "level": "VERBOSE",
@@ -3481,6 +3499,12 @@
       "group": "WM_DEBUG_CONFIGURATION",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "1999594750": {
+      "message": "startAnimation",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/NonAppWindowAnimationAdapter.java"
+    },
     "2018454757": {
       "message": "WS.removeImmediately: %s Already removed...",
       "level": "VERBOSE",
diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java
index da5162b..6fcd8d0 100644
--- a/graphics/java/android/graphics/RenderNode.java
+++ b/graphics/java/android/graphics/RenderNode.java
@@ -275,6 +275,8 @@
          * Call to apply a stretch effect to any child SurfaceControl layers
          *
          * TODO: Fold this into positionChanged & have HWUI do the ASurfaceControl calls?
+         *   (njawad) update to consume different stretch parameters for horizontal/vertical stretch
+         *   to ensure SkiaGLRenderEngine can also apply the same stretch to a surface
          *
          * @hide
          */
@@ -718,7 +720,7 @@
 
     /** @hide */
     public boolean stretch(float left, float top, float right, float bottom,
-            float vecX, float vecY, float maxStretchAmount) {
+            float vecX, float vecY, float maxStretchAmountX, float maxStretchAmountY) {
         if (Float.isInfinite(vecX) || Float.isNaN(vecX)) {
             throw new IllegalArgumentException("vecX must be a finite, non-NaN value " + vecX);
         }
@@ -730,9 +732,13 @@
                     "Stretch region must not be empty, got "
                             + new RectF(left, top, right, bottom).toString());
         }
-        if (maxStretchAmount <= 0.0f) {
+        if (maxStretchAmountX <= 0.0f) {
             throw new IllegalArgumentException(
-                    "The max stretch amount must be >0, got " + maxStretchAmount);
+                    "The max horizontal stretch amount must be >0, got " + maxStretchAmountX);
+        }
+        if (maxStretchAmountY <= 0.0f) {
+            throw new IllegalArgumentException(
+                    "The max vertical stretch amount must be >0, got " + maxStretchAmountY);
         }
         return nStretch(
                 mNativeRenderNode,
@@ -742,7 +748,8 @@
                 bottom,
                 vecX,
                 vecY,
-                maxStretchAmount
+                maxStretchAmountX,
+                maxStretchAmountY
         );
     }
 
@@ -1695,7 +1702,7 @@
 
     @CriticalNative
     private static native boolean nStretch(long renderNode, float left, float top, float right,
-            float bottom, float vecX, float vecY, float maxStretch);
+            float bottom, float vecX, float vecY, float maxStretchX, float maxStretchY);
 
     @CriticalNative
     private static native boolean nHasShadow(long renderNode);
diff --git a/graphics/java/android/graphics/drawable/RippleAnimationSession.java b/graphics/java/android/graphics/drawable/RippleAnimationSession.java
index b57f7af..94d5c22 100644
--- a/graphics/java/android/graphics/drawable/RippleAnimationSession.java
+++ b/graphics/java/android/graphics/drawable/RippleAnimationSession.java
@@ -26,8 +26,8 @@
 import android.graphics.Paint;
 import android.graphics.RecordingCanvas;
 import android.graphics.animation.RenderNodeAnimator;
-import android.util.ArraySet;
 import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
 import android.view.animation.LinearInterpolator;
 import android.view.animation.PathInterpolator;
 
@@ -41,8 +41,8 @@
     private static final int ENTER_ANIM_DURATION = 450;
     private static final int EXIT_ANIM_DURATION = 300;
     private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
-    private static final TimeInterpolator PATH_INTERPOLATOR =
-            new PathInterpolator(.2f, 0, 0, 1f);
+    private static final Interpolator FAST_OUT_LINEAR_IN =
+            new PathInterpolator(0.4f, 0f, 1f, 1f);
     private Consumer<RippleAnimationSession> mOnSessionEnd;
     private final AnimationProperties<Float, Paint> mProperties;
     private AnimationProperties<CanvasProperty<Float>, CanvasProperty<Paint>> mCanvasProperties;
@@ -59,7 +59,7 @@
         mSparkle.addUpdateListener(anim -> {
             final long now = AnimationUtils.currentAnimationTimeMillis();
             final long elapsed = now - mStartTime - ENTER_ANIM_DURATION;
-            final float phase = (float) elapsed / 30000f;
+            final float phase = (float) elapsed / 800;
             mProperties.getShader().setNoisePhase(phase);
             notifyUpdate();
         });
@@ -174,7 +174,7 @@
     private void startAnimation(Animator expand) {
         expand.setDuration(ENTER_ANIM_DURATION);
         expand.addListener(new AnimatorListener(this));
-        expand.setInterpolator(LINEAR_INTERPOLATOR);
+        expand.setInterpolator(FAST_OUT_LINEAR_IN);
         expand.start();
         if (!mSparkle.isRunning()) {
             mSparkle.start();
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index fb2b9b3..d5711c8 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -914,7 +914,7 @@
         shader.setColor(color);
         shader.setOrigin(w / 2, y / 2);
         shader.setTouch(x, y);
-        shader.setResolution(w, h);
+        shader.setResolution(w, h, mState.mDensity);
         shader.setNoisePhase(0);
         shader.setRadius(radius);
         shader.setProgress(.0f);
diff --git a/graphics/java/android/graphics/drawable/RippleShader.java b/graphics/java/android/graphics/drawable/RippleShader.java
index ea9ba32..5dd250c 100644
--- a/graphics/java/android/graphics/drawable/RippleShader.java
+++ b/graphics/java/android/graphics/drawable/RippleShader.java
@@ -20,13 +20,15 @@
 import android.graphics.Color;
 import android.graphics.RuntimeShader;
 import android.graphics.Shader;
+import android.util.DisplayMetrics;
 
 final class RippleShader extends RuntimeShader {
     private static final String SHADER_UNIFORMS =  "uniform vec2 in_origin;\n"
             + "uniform vec2 in_touch;\n"
             + "uniform float in_progress;\n"
             + "uniform float in_maxRadius;\n"
-            + "uniform vec2 in_resolution;\n"
+            + "uniform vec2 in_resolutionScale;\n"
+            + "uniform vec2 in_noiseScale;\n"
             + "uniform float in_hasMask;\n"
             + "uniform float in_noisePhase;\n"
             + "uniform vec4 in_color;\n"
@@ -40,18 +42,15 @@
             + "}"
             + "const float PI = 3.1415926535897932384626;\n"
             + "\n"
-            + "float threshold(float v, float l, float h) {\n"
-            + "  return step(l, v) * (1.0 - step(h, v));\n"
-            + "}\n"
-            + "\n"
             + "float sparkles(vec2 uv, float t) {\n"
             + "  float n = triangleNoise(uv);\n"
             + "  float s = 0.0;\n"
             + "  for (float i = 0; i < 4; i += 1) {\n"
-            + "    float l = i * 0.25;\n"
-            + "    float h = l + 0.005;\n"
-            + "    float o = abs(sin(0.1 * PI * (t + i)));\n"
-            + "    s += threshold(n + o, l, h);\n"
+            + "    float l = i * 0.01;\n"
+            + "    float h = l + 0.1;\n"
+            + "    float o = smoothstep(n - l, h, n);\n"
+            + "    o *= abs(sin(PI * o * (t + 0.55 * i)));\n"
+            + "    s += o;\n"
             + "  }\n"
             + "  return saturate(s);\n"
             + "}\n"
@@ -83,7 +82,9 @@
             + "    vec2 center = mix(in_touch, in_origin, fadeIn);\n"
             + "    float ring = getRingMask(p, center, in_maxRadius, fadeIn);\n"
             + "    float alpha = min(fadeIn, 1. - fadeOutNoise);\n"
-            + "    float sparkle = sparkles(p, in_noisePhase) * ring * alpha;\n"
+            + "    vec2 uv = p * in_resolutionScale;\n"
+            + "    vec2 densityUv = uv - mod(uv, in_noiseScale);\n"
+            + "    float sparkle = sparkles(densityUv, in_noisePhase) * ring * alpha;\n"
             + "    float fade = min(fadeIn, 1. - fadeOutRipple);\n"
             + "    vec4 circle = in_color * (softCircle(p, center, in_maxRadius "
             + "      * fadeIn, 0.2) * fade);\n"
@@ -135,7 +136,10 @@
                 color.green(), color.blue(), color.alpha()});
     }
 
-    public void setResolution(float w, float h) {
-        setUniform("in_resolution", w, h);
+    public void setResolution(float w, float h, int density) {
+        float noiseScale = 0.8f;
+        float densityScale = density * DisplayMetrics.DENSITY_DEFAULT_SCALE * 0.5f * noiseScale;
+        setUniform("in_resolutionScale", new float[] {1f / w, 1f / h});
+        setUniform("in_noiseScale", new float[] {densityScale / w, densityScale / h});
     }
 }
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java b/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
index 2ee952c..9d8a5ef 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
@@ -123,8 +123,9 @@
             throws InvalidKeyException {
         resetAll();
 
-        if (!(key instanceof AndroidKeyStorePrivateKey
-                || key instanceof AndroidKeyStoreSecretKey)) {
+        // Public key operations get diverted to the default provider.
+        if (!(key instanceof AndroidKeyStorePrivateKey)
+                && (key instanceof PrivateKey || key instanceof PublicKey)) {
             try {
                 mCipher = Cipher.getInstance(getTransform());
                 String transform = getTransform();
@@ -184,8 +185,9 @@
             SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
         resetAll();
 
-        if (!(key instanceof AndroidKeyStorePrivateKey
-                || key instanceof AndroidKeyStoreSecretKey)) {
+        // Public key operations get diverted to the default provider.
+        if (!(key instanceof AndroidKeyStorePrivateKey)
+                && (key instanceof PrivateKey || key instanceof PublicKey)) {
             try {
                 mCipher = Cipher.getInstance(getTransform());
                 mCipher.init(opmode, key, params, random);
@@ -213,8 +215,9 @@
             SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
         resetAll();
 
-        if (!(key instanceof AndroidKeyStorePrivateKey
-                || key instanceof AndroidKeyStoreSecretKey)) {
+        // Public key operations get diverted to the default provider.
+        if (!(key instanceof AndroidKeyStorePrivateKey)
+                && (key instanceof PrivateKey || key instanceof PublicKey)) {
             try {
                 mCipher = Cipher.getInstance(getTransform());
                 mCipher.init(opmode, key, params, random);
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index fa852e3..ba6d22f 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -145,23 +145,15 @@
         sInstalled = true;
 
         Security.addProvider(new AndroidKeyStoreProvider());
-        Security.addProvider(
-                new android.security.keystore.AndroidKeyStoreProvider(
-                        "AndroidKeyStoreLegacy"));
         Provider workaroundProvider = new AndroidKeyStoreBCWorkaroundProvider();
-        Provider legacyWorkaroundProvider =
-                new android.security.keystore.AndroidKeyStoreBCWorkaroundProvider(
-                        "AndroidKeyStoreBCWorkaroundLegacy");
         if (bcProviderIndex != -1) {
             // Bouncy Castle provider found -- install the workaround provider above it.
             // insertProviderAt uses 1-based positions.
-            Security.insertProviderAt(legacyWorkaroundProvider, bcProviderIndex + 1);
             Security.insertProviderAt(workaroundProvider, bcProviderIndex + 1);
         } else {
             // Bouncy Castle provider not found -- install the workaround provider at lowest
             // priority.
             Security.addProvider(workaroundProvider);
-            Security.addProvider(legacyWorkaroundProvider);
         }
     }
 
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 1b5dc8b..3f03302 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -38,6 +38,14 @@
     path: "src",
 }
 
+filegroup {
+    name: "wm_shell-aidls",
+    srcs: [
+        "src/**/*.aidl",
+    ],
+    path: "src",
+}
+
 // TODO(b/168581922) protologtool do not support kotlin(*.kt)
 filegroup {
     name: "wm_shell-sources-kt",
@@ -98,7 +106,7 @@
         ":wm_shell_protolog_src",
         // TODO(b/168581922) protologtool do not support kotlin(*.kt)
         ":wm_shell-sources-kt",
-        "src/**/I*.aidl",
+        ":wm_shell-aidls",
     ],
     resource_dirs: [
         "res",
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
index eaed24d..d451f4a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
@@ -47,21 +47,7 @@
     private final ShellExecutor mMainExecutor;
     private final HandlerImpl mImpl = new HandlerImpl();
 
-    public static ShellCommandHandler create(
-            ShellTaskOrganizer shellTaskOrganizer,
-            Optional<LegacySplitScreenController> legacySplitScreenOptional,
-            Optional<SplitScreenController> splitScreenOptional,
-            Optional<Pip> pipOptional,
-            Optional<OneHandedController> oneHandedOptional,
-            Optional<HideDisplayCutoutController> hideDisplayCutout,
-            Optional<AppPairsController> appPairsOptional,
-            ShellExecutor mainExecutor) {
-        return new ShellCommandHandlerImpl(shellTaskOrganizer, legacySplitScreenOptional,
-                splitScreenOptional, pipOptional, oneHandedOptional, hideDisplayCutout,
-                appPairsOptional, mainExecutor).mImpl;
-    }
-
-    private ShellCommandHandlerImpl(
+    public ShellCommandHandlerImpl(
             ShellTaskOrganizer shellTaskOrganizer,
             Optional<LegacySplitScreenController> legacySplitScreenOptional,
             Optional<SplitScreenController> splitScreenOptional,
@@ -80,6 +66,10 @@
         mMainExecutor = mainExecutor;
     }
 
+    public ShellCommandHandler asShellCommandHandler() {
+        return mImpl;
+    }
+
     /** Dumps WM Shell internal state. */
     private void dump(PrintWriter pw) {
         mShellTaskOrganizer.dump(pw, "");
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 85bd24c..6f4550c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
@@ -26,7 +26,7 @@
 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.startingsurface.StartingWindowController;
 import com.android.wm.shell.transition.Transitions;
 
 import java.util.Optional;
@@ -47,44 +47,20 @@
     private final FullscreenTaskListener mFullscreenTaskListener;
     private final ShellExecutor mMainExecutor;
     private final Transitions mTransitions;
-    private final Optional<StartingSurface> mStartingSurfaceOptional;
+    private final StartingWindowController mStartingWindow;
 
     private final InitImpl mImpl = new InitImpl();
 
-    public static ShellInit create(DisplayImeController displayImeController,
+    public ShellInitImpl(DisplayImeController displayImeController,
             DragAndDropController dragAndDropController,
             ShellTaskOrganizer shellTaskOrganizer,
             Optional<LegacySplitScreenController> legacySplitScreenOptional,
             Optional<SplitScreenController> splitScreenOptional,
             Optional<AppPairsController> appPairsOptional,
-            Optional<StartingSurface> startingSurfaceOptional,
             Optional<PipTouchHandler> pipTouchHandlerOptional,
             FullscreenTaskListener fullscreenTaskListener,
             Transitions transitions,
-            ShellExecutor mainExecutor) {
-        return new ShellInitImpl(displayImeController,
-                dragAndDropController,
-                shellTaskOrganizer,
-                legacySplitScreenOptional,
-                splitScreenOptional,
-                appPairsOptional,
-                startingSurfaceOptional,
-                pipTouchHandlerOptional,
-                fullscreenTaskListener,
-                transitions,
-                mainExecutor).mImpl;
-    }
-
-    private ShellInitImpl(DisplayImeController displayImeController,
-            DragAndDropController dragAndDropController,
-            ShellTaskOrganizer shellTaskOrganizer,
-            Optional<LegacySplitScreenController> legacySplitScreenOptional,
-            Optional<SplitScreenController> splitScreenOptional,
-            Optional<AppPairsController> appPairsOptional,
-            Optional<StartingSurface> startingSurfaceOptional,
-            Optional<PipTouchHandler> pipTouchHandlerOptional,
-            FullscreenTaskListener fullscreenTaskListener,
-            Transitions transitions,
+            StartingWindowController startingWindow,
             ShellExecutor mainExecutor) {
         mDisplayImeController = displayImeController;
         mDragAndDropController = dragAndDropController;
@@ -96,17 +72,21 @@
         mPipTouchHandlerOptional = pipTouchHandlerOptional;
         mTransitions = transitions;
         mMainExecutor = mainExecutor;
-        mStartingSurfaceOptional = startingSurfaceOptional;
+        mStartingWindow = startingWindow;
+    }
+
+    public ShellInit asShellInit() {
+        return mImpl;
     }
 
     private void init() {
         // Start listening for display changes
         mDisplayImeController.startMonitorDisplays();
 
+        // Setup the shell organizer
         mShellTaskOrganizer.addListenerForType(
                 mFullscreenTaskListener, TASK_LISTENER_TYPE_FULLSCREEN);
-        mStartingSurfaceOptional.ifPresent(mShellTaskOrganizer::initStartingSurface);
-        // Register the shell organizer
+        mShellTaskOrganizer.initStartingWindow(mStartingWindow);
         mShellTaskOrganizer.registerOrganizer();
 
         mAppPairsOptional.ifPresent(AppPairsController::onOrganizerRegistered);
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 fcb53cd..94d13ea 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -48,7 +48,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.StartingSurface;
+import com.android.wm.shell.startingsurface.StartingWindowController;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -133,7 +133,7 @@
     private final ArraySet<LocusIdListener> mLocusIdListeners = new ArraySet<>();
 
     private final Object mLock = new Object();
-    private StartingSurface mStartingSurface;
+    private StartingWindowController mStartingWindow;
 
     /**
      * In charge of showing size compat UI. Can be {@code null} if device doesn't support size
@@ -184,8 +184,8 @@
     /**
      * @hide
      */
-    public void initStartingSurface(StartingSurface startingSurface) {
-        mStartingSurface = startingSurface;
+    public void initStartingWindow(StartingWindowController startingWindow) {
+        mStartingWindow = startingWindow;
     }
 
     /**
@@ -302,23 +302,23 @@
 
     @Override
     public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
-        if (mStartingSurface != null) {
-            mStartingSurface.addStartingWindow(info, appToken);
+        if (mStartingWindow != null) {
+            mStartingWindow.addStartingWindow(info, appToken);
         }
     }
 
     @Override
     public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
             boolean playRevealAnimation) {
-        if (mStartingSurface != null) {
-            mStartingSurface.removeStartingWindow(taskId, leash, frame, playRevealAnimation);
+        if (mStartingWindow != null) {
+            mStartingWindow.removeStartingWindow(taskId, leash, frame, playRevealAnimation);
         }
     }
 
     @Override
     public void copySplashScreenView(int taskId) {
-        if (mStartingSurface != null) {
-            mStartingSurface.copySplashScreenView(taskId);
+        if (mStartingWindow != null) {
+            mStartingWindow.copySplashScreenView(taskId);
         }
     }
 
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 16ede73..e5c9e25 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
@@ -151,6 +151,7 @@
      * starting a new animation.
      */
     private final ShellExecutor mDelayedAnimationExecutor;
+    private Runnable mDelayedAnimation;
 
     /**
      * Interface to synchronize {@link View} state and the screen.
@@ -1865,7 +1866,7 @@
             mExpandedBubble.getExpandedView().setAlphaAnimating(true);
         }
 
-        mDelayedAnimationExecutor.executeDelayed(() -> {
+        mDelayedAnimation = () -> {
             mExpandedViewAlphaAnimator.start();
 
             PhysicsAnimator.getInstance(mExpandedViewContainerMatrix).cancel();
@@ -1898,7 +1899,8 @@
                         }
                     })
                     .start();
-        }, startDelay);
+        };
+        mDelayedAnimationExecutor.executeDelayed(mDelayedAnimation, startDelay);
     }
 
     private void animateCollapse() {
@@ -2097,7 +2099,7 @@
      * animating flags for those animations.
      */
     private void cancelDelayedExpandCollapseSwitchAnimations() {
-        mDelayedAnimationExecutor.removeAllCallbacks();
+        mDelayedAnimationExecutor.removeCallbacks(mDelayedAnimation);
 
         mIsExpansionAnimating = false;
         mIsBubbleSwitchAnimating = false;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ExecutorUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ExecutorUtils.java
new file mode 100644
index 0000000..b29058b
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ExecutorUtils.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.common;
+
+import android.Manifest;
+import android.util.Slog;
+
+import java.util.function.Consumer;
+
+/**
+ * Helpers for working with executors
+ */
+public class ExecutorUtils {
+
+    /**
+     * Checks that the caller has the MANAGE_ACTIVITY_TASKS permission and executes the given
+     * callback.
+     */
+    public static <T> void executeRemoteCallWithTaskPermission(RemoteCallable<T> controllerInstance,
+            String log, Consumer<T> callback) {
+        executeRemoteCallWithTaskPermission(controllerInstance, log, callback,
+                false /* blocking */);
+    }
+
+    /**
+     * Checks that the caller has the MANAGE_ACTIVITY_TASKS permission and executes the given
+     * callback.
+     */
+    public static <T> void executeRemoteCallWithTaskPermission(RemoteCallable<T> controllerInstance,
+            String log, Consumer<T> callback, boolean blocking) {
+        if (controllerInstance == null) return;
+
+        final RemoteCallable<T> controller = controllerInstance;
+        controllerInstance.getContext().enforceCallingPermission(
+                Manifest.permission.MANAGE_ACTIVITY_TASKS, log);
+        if (blocking) {
+            try {
+                controllerInstance.getRemoteCallExecutor().executeBlocking(() -> {
+                    callback.accept((T) controller);
+                });
+            } catch (InterruptedException e) {
+                Slog.e("ExecutorUtils", "Remote call failed", e);
+            }
+        } else {
+            controllerInstance.getRemoteCallExecutor().execute(() -> {
+                callback.accept((T) controller);
+            });
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/HandlerExecutor.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/HandlerExecutor.java
index a4cd3c5..bfee820 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/HandlerExecutor.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/HandlerExecutor.java
@@ -18,7 +18,6 @@
 
 import android.annotation.NonNull;
 import android.os.Handler;
-import android.os.Looper;
 
 /** Executor implementation which is backed by a Handler. */
 public class HandlerExecutor implements ShellExecutor {
@@ -47,11 +46,6 @@
     }
 
     @Override
-    public void removeAllCallbacks() {
-        mHandler.removeCallbacksAndMessages(null);
-    }
-
-    @Override
     public void removeCallbacks(@NonNull Runnable r) {
         mHandler.removeCallbacks(r);
     }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/common/RemoteCallable.java
similarity index 61%
copy from packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl
copy to libs/WindowManager/Shell/src/com/android/wm/shell/common/RemoteCallable.java
index 54242be..30f535b 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/RemoteCallable.java
@@ -14,12 +14,21 @@
  * limitations under the License.
  */
 
-package com.android.systemui.shared.recents;
+package com.android.wm.shell.common;
+
+import android.content.Context;
 
 /**
- * Listener interface that Launcher attaches to SystemUI to get split-screen callbacks.
+ * An interface for controllers that can receive remote calls.
  */
-oneway interface ISplitScreenListener {
-    void onStagePositionChanged(int stage, int position);
-    void onTaskStageChanged(int taskId, int stage, boolean visible);
-}
+public interface RemoteCallable<T> {
+    /**
+     * Returns a context used for permission checking.
+     */
+    Context getContext();
+
+    /**
+     * Returns the executor to post the handler callback to.
+     */
+    ShellExecutor getRemoteCallExecutor();
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java
index 6abc8f6..f729164 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java
@@ -16,16 +16,10 @@
 
 package com.android.wm.shell.common;
 
-import android.os.Looper;
-import android.os.SystemClock;
-import android.os.Trace;
-
 import java.lang.reflect.Array;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
-import java.util.function.BooleanSupplier;
-import java.util.function.Predicate;
 import java.util.function.Supplier;
 
 /**
@@ -94,11 +88,6 @@
     void executeDelayed(Runnable runnable, long delayMillis);
 
     /**
-     * Removes all pending callbacks.
-     */
-    void removeAllCallbacks();
-
-    /**
      * See {@link android.os.Handler#removeCallbacks}.
      */
     void removeCallbacks(Runnable runnable);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
index aab2334..9a09ca4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -235,7 +235,7 @@
             mStarter.startShortcut(packageName, id, stage, position, opts, user);
         } else {
             mStarter.startIntent(intent.getParcelableExtra(EXTRA_PENDING_INTENT),
-                    mContext, null, stage, position, opts);
+                    null, stage, position, opts);
         }
     }
 
@@ -295,7 +295,7 @@
                 @Nullable Bundle options);
         void startShortcut(String packageName, String shortcutId, @StageType int stage,
                 @StagePosition int position, @Nullable Bundle options, UserHandle user);
-        void startIntent(PendingIntent intent, Context context, Intent fillInIntent,
+        void startIntent(PendingIntent intent, Intent fillInIntent,
                 @StageType int stage, @StagePosition int position,
                 @Nullable Bundle options);
         void enterSplitScreen(int taskId, boolean leftOrTop);
@@ -337,9 +337,8 @@
         }
 
         @Override
-        public void startIntent(PendingIntent intent, Context context,
-                @Nullable Intent fillInIntent, int stage, int position,
-                @Nullable Bundle options) {
+        public void startIntent(PendingIntent intent, @Nullable Intent fillInIntent, int stage,
+                int position, @Nullable Bundle options) {
             try {
                 intent.send(mContext, 0, fillInIntent, null, null, null, options);
             } catch (PendingIntent.CanceledException e) {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/IOneHanded.aidl
similarity index 66%
copy from packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl
copy to libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/IOneHanded.aidl
index 54242be..008b508 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/IOneHanded.aidl
@@ -14,12 +14,20 @@
  * limitations under the License.
  */
 
-package com.android.systemui.shared.recents;
+package com.android.wm.shell.onehanded;
 
 /**
- * Listener interface that Launcher attaches to SystemUI to get split-screen callbacks.
+ * Interface that is exposed to remote callers to manipulate the OneHanded feature.
  */
-oneway interface ISplitScreenListener {
-    void onStagePositionChanged(int stage, int position);
-    void onTaskStageChanged(int taskId, int stage, boolean visible);
+interface IOneHanded {
+
+    /**
+     * Enters one handed mode.
+     */
+    oneway void startOneHanded() = 1;
+
+    /**
+     * Exits one handed mode.
+     */
+    oneway void stopOneHanded() = 2;
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java
index 4f31c37..a7e9a01 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java
@@ -26,6 +26,14 @@
  */
 @ExternalThread
 public interface OneHanded {
+
+    /**
+     * Returns a binder that can be passed to an external process to manipulate OneHanded.
+     */
+    default IOneHanded createExternalInterface() {
+        return null;
+    }
+
     /**
      * Return one handed settings enabled or not.
      */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index 44dad57..25968eb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -18,6 +18,10 @@
 
 import static android.os.UserHandle.USER_CURRENT;
 
+import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
+
+import android.Manifest;
+import android.annotation.BinderThread;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.om.IOverlayManager;
@@ -43,6 +47,8 @@
 import com.android.wm.shell.R;
 import com.android.wm.shell.common.DisplayChangeController;
 import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.ExecutorUtils;
+import com.android.wm.shell.common.RemoteCallable;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.TaskStackListenerCallback;
 import com.android.wm.shell.common.TaskStackListenerImpl;
@@ -54,7 +60,7 @@
 /**
  * Manages and manipulates the one handed states, transitions, and gesture for phones.
  */
-public class OneHandedController {
+public class OneHandedController implements RemoteCallable<OneHandedController> {
     private static final String TAG = "OneHandedController";
 
     private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE =
@@ -73,6 +79,7 @@
     private final Context mContext;
     private final DisplayController mDisplayController;
     private final OneHandedGestureHandler mGestureHandler;
+    private final OneHandedSettingsUtil mOneHandedSettingsUtil;
     private final OneHandedTimeoutHandler mTimeoutHandler;
     private final OneHandedTouchHandler mTouchHandler;
     private final OneHandedTutorialHandler mTutorialHandler;
@@ -108,8 +115,12 @@
             new AccessibilityManager.AccessibilityStateChangeListener() {
                 @Override
                 public void onAccessibilityStateChanged(boolean enabled) {
+                    if (mOneHandedSettingsUtil == null) {
+                        Slog.w(TAG, "mOneHandedSettingsUtil may not instantiate yet");
+                        return;
+                    }
                     if (enabled) {
-                        final int mOneHandedTimeout = OneHandedSettingsUtil
+                        final int mOneHandedTimeout = mOneHandedSettingsUtil
                                 .getSettingsOneHandedModeTimeout(mContext.getContentResolver());
                         final int timeout = mAccessibilityManager
                                 .getRecommendedTimeoutMillis(mOneHandedTimeout * 1000
@@ -117,7 +128,7 @@
                                         AccessibilityManager.FLAG_CONTENT_CONTROLS);
                         mTimeoutHandler.setTimeout(timeout / 1000);
                     } else {
-                        mTimeoutHandler.setTimeout(OneHandedSettingsUtil
+                        mTimeoutHandler.setTimeout(mOneHandedSettingsUtil
                                 .getSettingsOneHandedModeTimeout(mContext.getContentResolver()));
                     }
                 }
@@ -166,13 +177,14 @@
         OneHandedDisplayAreaOrganizer organizer = new OneHandedDisplayAreaOrganizer(
                 context, windowManager, animationController, tutorialHandler,
                 oneHandedBackgroundPanelOrganizer, mainExecutor);
+        OneHandedSettingsUtil settingsUtil = new OneHandedSettingsUtil();
         OneHandedUiEventLogger oneHandedUiEventsLogger = new OneHandedUiEventLogger(uiEventLogger);
         IOverlayManager overlayManager = IOverlayManager.Stub.asInterface(
                 ServiceManager.getService(Context.OVERLAY_SERVICE));
         return new OneHandedController(context, windowManager, displayController,
                 oneHandedBackgroundPanelOrganizer, organizer, touchHandler, tutorialHandler,
-                gestureHandler, timeoutHandler, oneHandedUiEventsLogger, overlayManager,
-                taskStackListener, mainExecutor, mainHandler);
+                gestureHandler, settingsUtil, timeoutHandler, oneHandedUiEventsLogger,
+                overlayManager, taskStackListener, mainExecutor, mainHandler);
     }
 
     @VisibleForTesting
@@ -184,6 +196,7 @@
             OneHandedTouchHandler touchHandler,
             OneHandedTutorialHandler tutorialHandler,
             OneHandedGestureHandler gestureHandler,
+            OneHandedSettingsUtil settingsUtil,
             OneHandedTimeoutHandler timeoutHandler,
             OneHandedUiEventLogger uiEventsLogger,
             IOverlayManager overlayManager,
@@ -191,6 +204,7 @@
             ShellExecutor mainExecutor,
             Handler mainHandler) {
         mContext = context;
+        mOneHandedSettingsUtil = settingsUtil;
         mWindowManager = windowManager;
         mBackgroundPanelOrganizer = backgroundPanelOrganizer;
         mDisplayAreaOrganizer = displayAreaOrganizer;
@@ -209,10 +223,10 @@
         final int sysPropPercentageConfig = SystemProperties.getInt(
                 ONE_HANDED_MODE_OFFSET_PERCENTAGE, Math.round(offsetPercentageConfig * 100.0f));
         mOffSetFraction = sysPropPercentageConfig / 100.0f;
-        mIsOneHandedEnabled = OneHandedSettingsUtil.getSettingsOneHandedModeEnabled(
+        mIsOneHandedEnabled = mOneHandedSettingsUtil.getSettingsOneHandedModeEnabled(
                 context.getContentResolver());
         mIsSwipeToNotificationEnabled =
-                OneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled(
+                mOneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled(
                         context.getContentResolver());
         mTimeoutHandler = timeoutHandler;
 
@@ -239,6 +253,16 @@
         return mImpl;
     }
 
+    @Override
+    public Context getContext() {
+        return mContext;
+    }
+
+    @Override
+    public ShellExecutor getRemoteCallExecutor() {
+        return mMainExecutor;
+    }
+
     /**
      * Set one handed enabled or disabled when user update settings
      */
@@ -325,25 +349,25 @@
     }
 
     private void setupSettingObservers() {
-        OneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.ONE_HANDED_MODE_ENABLED,
+        mOneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.ONE_HANDED_MODE_ENABLED,
                 mContext.getContentResolver(), mEnabledObserver);
-        OneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.ONE_HANDED_MODE_TIMEOUT,
+        mOneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.ONE_HANDED_MODE_TIMEOUT,
                 mContext.getContentResolver(), mTimeoutObserver);
-        OneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.TAPS_APP_TO_EXIT,
+        mOneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.TAPS_APP_TO_EXIT,
                 mContext.getContentResolver(), mTaskChangeExitObserver);
-        OneHandedSettingsUtil.registerSettingsKeyObserver(
+        mOneHandedSettingsUtil.registerSettingsKeyObserver(
                 Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED,
                 mContext.getContentResolver(), mSwipeToNotificationEnabledObserver);
     }
 
     private void updateSettings() {
-        setOneHandedEnabled(OneHandedSettingsUtil
+        setOneHandedEnabled(mOneHandedSettingsUtil
                 .getSettingsOneHandedModeEnabled(mContext.getContentResolver()));
-        mTimeoutHandler.setTimeout(OneHandedSettingsUtil
+        mTimeoutHandler.setTimeout(mOneHandedSettingsUtil
                 .getSettingsOneHandedModeTimeout(mContext.getContentResolver()));
-        setTaskChangeToExit(OneHandedSettingsUtil
+        setTaskChangeToExit(mOneHandedSettingsUtil
                 .getSettingsTapsAppToExit(mContext.getContentResolver()));
-        setSwipeToNotificationEnabled(OneHandedSettingsUtil
+        setSwipeToNotificationEnabled(mOneHandedSettingsUtil
                 .getSettingsSwipeToNotificationEnabled(mContext.getContentResolver()));
     }
 
@@ -358,7 +382,7 @@
 
     @VisibleForTesting
     void onEnabledSettingChanged() {
-        final boolean enabled = OneHandedSettingsUtil.getSettingsOneHandedModeEnabled(
+        final boolean enabled = mOneHandedSettingsUtil.getSettingsOneHandedModeEnabled(
                 mContext.getContentResolver());
         mOneHandedUiEventLogger.writeEvent(enabled
                 ? OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_ENABLED_ON
@@ -368,13 +392,13 @@
 
         // Also checks swipe to notification settings since they all need gesture overlay.
         setEnabledGesturalOverlay(
-                enabled || OneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled(
+                enabled || mOneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled(
                         mContext.getContentResolver()));
     }
 
     @VisibleForTesting
     void onTimeoutSettingChanged() {
-        final int newTimeout = OneHandedSettingsUtil.getSettingsOneHandedModeTimeout(
+        final int newTimeout = mOneHandedSettingsUtil.getSettingsOneHandedModeTimeout(
                 mContext.getContentResolver());
         int metricsId = OneHandedUiEventLogger.OneHandedSettingsTogglesEvent.INVALID.getId();
         switch (newTimeout) {
@@ -403,7 +427,7 @@
 
     @VisibleForTesting
     void onTaskChangeExitSettingChanged() {
-        final boolean enabled = OneHandedSettingsUtil.getSettingsTapsAppToExit(
+        final boolean enabled = mOneHandedSettingsUtil.getSettingsTapsAppToExit(
                 mContext.getContentResolver());
         mOneHandedUiEventLogger.writeEvent(enabled
                 ? OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_APP_TAPS_EXIT_ON
@@ -415,13 +439,13 @@
     @VisibleForTesting
     void onSwipeToNotificationEnabledSettingChanged() {
         final boolean enabled =
-                OneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled(
+                mOneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled(
                         mContext.getContentResolver());
         setSwipeToNotificationEnabled(enabled);
 
         // Also checks one handed mode settings since they all need gesture overlay.
         setEnabledGesturalOverlay(
-                enabled || OneHandedSettingsUtil.getSettingsOneHandedModeEnabled(
+                enabled || mOneHandedSettingsUtil.getSettingsOneHandedModeEnabled(
                         mContext.getContentResolver()));
     }
 
@@ -480,7 +504,8 @@
     }
 
     private void setupGesturalOverlay() {
-        if (!OneHandedSettingsUtil.getSettingsOneHandedModeEnabled(mContext.getContentResolver())) {
+        if (!mOneHandedSettingsUtil.getSettingsOneHandedModeEnabled(
+                mContext.getContentResolver())) {
             return;
         }
 
@@ -551,7 +576,7 @@
             mTutorialHandler.dump(pw);
         }
 
-        OneHandedSettingsUtil.dump(pw, innerPrefix, mContext.getContentResolver());
+        mOneHandedSettingsUtil.dump(pw, innerPrefix, mContext.getContentResolver());
 
         if (mOverlayManager != null) {
             OverlayInfo info = null;
@@ -567,8 +592,22 @@
         }
     }
 
+    /**
+     * The interface for calls from outside the Shell, within the host process.
+     */
     @ExternalThread
     private class OneHandedImpl implements OneHanded {
+        private IOneHandedImpl mIOneHanded;
+
+        @Override
+        public IOneHanded createExternalInterface() {
+            if (mIOneHanded != null) {
+                mIOneHanded.invalidate();
+            }
+            mIOneHanded = new IOneHandedImpl(OneHandedController.this);
+            return mIOneHanded;
+        }
+
         @Override
         public boolean isOneHandedEnabled() {
             // This is volatile so return directly
@@ -637,4 +676,39 @@
             });
         }
     }
+
+    /**
+     * The interface for calls from outside the host process.
+     */
+    @BinderThread
+    private static class IOneHandedImpl extends IOneHanded.Stub {
+        private OneHandedController mController;
+
+        IOneHandedImpl(OneHandedController controller) {
+            mController = controller;
+        }
+
+        /**
+         * Invalidates this instance, preventing future calls from updating the controller.
+         */
+        void invalidate() {
+            mController = null;
+        }
+
+        @Override
+        public void startOneHanded() {
+            executeRemoteCallWithTaskPermission(mController, "startOneHanded",
+                    (controller) -> {
+                        controller.startOneHanded();
+                    });
+        }
+
+        @Override
+        public void stopOneHanded() {
+            executeRemoteCallWithTaskPermission(mController, "stopOneHanded",
+                    (controller) -> {
+                        controller.stopOneHanded();
+                    });
+        }
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
index f8217c6..4768cf5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
@@ -67,7 +67,7 @@
      * @param observer Observer from caller
      * @return uri key for observing
      */
-    public static Uri registerSettingsKeyObserver(String key, ContentResolver resolver,
+    public Uri registerSettingsKeyObserver(String key, ContentResolver resolver,
             ContentObserver observer) {
         Uri uriKey = null;
         uriKey = Settings.Secure.getUriFor(key);
@@ -83,7 +83,7 @@
      * @param resolver ContentResolver of context
      * @param observer preference key change observer
      */
-    public static void unregisterSettingsKeyObserver(ContentResolver resolver,
+    public void unregisterSettingsKeyObserver(ContentResolver resolver,
             ContentObserver observer) {
         if (resolver != null) {
             resolver.unregisterContentObserver(observer);
@@ -95,7 +95,7 @@
      *
      * @return enable or disable one handed mode flag.
      */
-    public static boolean getSettingsOneHandedModeEnabled(ContentResolver resolver) {
+    public boolean getSettingsOneHandedModeEnabled(ContentResolver resolver) {
         return Settings.Secure.getInt(resolver,
                 Settings.Secure.ONE_HANDED_MODE_ENABLED, 0 /* Disabled */) == 1;
     }
@@ -105,7 +105,7 @@
      *
      * @return enable or disable taps app exit.
      */
-    public static boolean getSettingsTapsAppToExit(ContentResolver resolver) {
+    public boolean getSettingsTapsAppToExit(ContentResolver resolver) {
         return Settings.Secure.getInt(resolver,
                 Settings.Secure.TAPS_APP_TO_EXIT, 0) == 1;
     }
@@ -116,7 +116,7 @@
      *
      * @return timeout value in seconds.
      */
-    public static @OneHandedTimeout int getSettingsOneHandedModeTimeout(ContentResolver resolver) {
+    public @OneHandedTimeout int getSettingsOneHandedModeTimeout(ContentResolver resolver) {
         return Settings.Secure.getInt(resolver,
                 Settings.Secure.ONE_HANDED_MODE_TIMEOUT, ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS);
     }
@@ -124,12 +124,12 @@
     /**
      * Returns whether swipe bottom to notification gesture enabled or not.
      */
-    public static boolean getSettingsSwipeToNotificationEnabled(ContentResolver resolver) {
+    public boolean getSettingsSwipeToNotificationEnabled(ContentResolver resolver) {
         return Settings.Secure.getInt(resolver,
                 Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, 1) == 1;
     }
 
-    protected static void dump(PrintWriter pw, String prefix, ContentResolver resolver) {
+    void dump(PrintWriter pw, String prefix, ContentResolver resolver) {
         final String innerPrefix = prefix + "  ";
         pw.println(prefix + TAG);
         pw.print(innerPrefix + "isOneHandedModeEnable=");
@@ -139,6 +139,6 @@
         pw.print(innerPrefix + "tapsAppToExit=");
         pw.println(getSettingsTapsAppToExit(resolver));
     }
-
-    private OneHandedSettingsUtil() {}
+    public OneHandedSettingsUtil() {
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
new file mode 100644
index 0000000..a6ffa6e
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
@@ -0,0 +1,63 @@
+/*
+ * 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.pip;
+
+import android.app.PictureInPictureParams;
+import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
+import android.graphics.Rect;
+
+import com.android.wm.shell.pip.IPipAnimationListener;
+
+/**
+ * Interface that is exposed to remote callers to manipulate the Pip feature.
+ */
+interface IPip {
+
+    /**
+     * Notifies that Activity is about to be swiped to home with entering PiP transition and
+     * queries the destination bounds for PiP depends on Launcher's rotation and shelf height.
+     *
+     * @param componentName ComponentName represents the Activity
+     * @param activityInfo ActivityInfo tied to the Activity
+     * @param pictureInPictureParams PictureInPictureParams tied to the Activity
+     * @param launcherRotation Launcher rotation to calculate the PiP destination bounds
+     * @param shelfHeight Shelf height of launcher to calculate the PiP destination bounds
+     * @return destination bounds the PiP window should land into
+     */
+    Rect startSwipePipToHome(in ComponentName componentName, in ActivityInfo activityInfo,
+                in PictureInPictureParams pictureInPictureParams,
+                int launcherRotation, int shelfHeight) = 1;
+
+    /**
+     * Notifies the swiping Activity to PiP onto home transition is finished
+     *
+     * @param componentName ComponentName represents the Activity
+     * @param destinationBounds the destination bounds the PiP window lands into
+     */
+    oneway void stopSwipePipToHome(in ComponentName componentName, in Rect destinationBounds) = 2;
+
+    /**
+     * Sets listener to get pinned stack animation callbacks.
+     */
+    oneway void setPinnedStackAnimationListener(IPipAnimationListener listener) = 3;
+
+    /**
+     * Sets the shelf height and visibility.
+     */
+    oneway void setShelfHeight(boolean visible, int shelfHeight) = 4;
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IPinnedStackAnimationListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl
similarity index 68%
rename from packages/SystemUI/shared/src/com/android/systemui/shared/recents/IPinnedStackAnimationListener.aidl
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl
index 97aa512..2569b78 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IPinnedStackAnimationListener.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl
@@ -14,15 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.systemui.shared.recents;
+package com.android.wm.shell.pip;
 
 /**
- * Listener interface that Launcher attaches to SystemUI to get
- * pinned stack animation callbacks.
+ * Listener interface that Launcher attaches to SystemUI to get Pip animation callbacks.
  */
-oneway interface IPinnedStackAnimationListener {
+oneway interface IPipAnimationListener {
     /**
-     * Notifies the pinned stack animation is started.
+     * Notifies the listener that the Pip animation is started.
      */
-    void onPinnedStackAnimationStarted();
+    void onPipAnimationStarted();
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
index d14c3e3c..6d4773b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
@@ -16,15 +16,10 @@
 
 package com.android.wm.shell.pip;
 
-import android.annotation.Nullable;
-import android.app.PictureInPictureParams;
-import android.content.ComponentName;
-import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 
 import com.android.wm.shell.common.annotations.ExternalThread;
-import com.android.wm.shell.pip.phone.PipTouchHandler;
 
 import java.io.PrintWriter;
 import java.util.function.Consumer;
@@ -34,6 +29,14 @@
  */
 @ExternalThread
 public interface Pip {
+
+    /**
+     * Returns a binder that can be passed to an external process to manipulate PIP.
+     */
+    default IPip createExternalInterface() {
+        return null;
+    }
+
     /**
      * Expand PIP, it's possible that specific request to activate the window via Alt-tab.
      */
@@ -109,30 +112,6 @@
     default void showPictureInPictureMenu() {}
 
     /**
-     * Called by Launcher when swiping an auto-pip enabled Activity to home starts
-     * @param componentName {@link ComponentName} represents the Activity entering PiP
-     * @param activityInfo {@link ActivityInfo} tied to the Activity
-     * @param pictureInPictureParams {@link PictureInPictureParams} tied to the Activity
-     * @param launcherRotation Rotation Launcher is in
-     * @param shelfHeight Shelf height when landing PiP window onto Launcher
-     * @return Destination bounds of PiP window based on the parameters passed in
-     */
-    default Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
-            PictureInPictureParams pictureInPictureParams,
-            int launcherRotation, int shelfHeight) {
-        return null;
-    }
-
-    /**
-     * Called by Launcher when swiping an auto-pip enable Activity to home finishes
-     * @param componentName {@link ComponentName} represents the Activity entering PiP
-     * @param destinationBounds Destination bounds of PiP window
-     */
-    default void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) {
-        return;
-    }
-
-    /**
      * Called by NavigationBar in order to listen in for PiP bounds change. This is mostly used
      * for times where the PiP bounds could conflict with SystemUI elements, such as a stashed
      * PiP and the Back-from-Edge gesture.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
index cb39b4e..e3594d0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
@@ -35,6 +35,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
+import java.util.function.Consumer;
 
 /**
  * Singleton source of truth for the current state of PIP bounds.
@@ -84,6 +85,7 @@
 
     private @Nullable Runnable mOnMinimalSizeChangeCallback;
     private @Nullable TriConsumer<Boolean, Integer, Boolean> mOnShelfVisibilityChangeCallback;
+    private @Nullable Consumer<Rect> mOnPipExclusionBoundsChangeCallback;
 
     public PipBoundsState(@NonNull Context context) {
         mContext = context;
@@ -102,6 +104,9 @@
     /** Set the current PIP bounds. */
     public void setBounds(@NonNull Rect bounds) {
         mBounds.set(bounds);
+        if (mOnPipExclusionBoundsChangeCallback != null) {
+            mOnPipExclusionBoundsChangeCallback.accept(bounds);
+        }
     }
 
     /** Get the current PIP bounds. */
@@ -386,6 +391,18 @@
         mOnShelfVisibilityChangeCallback = onShelfVisibilityChangeCallback;
     }
 
+    /**
+     * Set a callback to watch out for PiP bounds. This is mostly used by SystemUI's
+     * Back-gesture handler, to avoid conflicting with PiP when it's stashed.
+     */
+    public void setPipExclusionBoundsChangeCallback(
+            @Nullable Consumer<Rect> onPipExclusionBoundsChangeCallback) {
+        mOnPipExclusionBoundsChangeCallback = onPipExclusionBoundsChangeCallback;
+        if (mOnPipExclusionBoundsChangeCallback != null) {
+            mOnPipExclusionBoundsChangeCallback.accept(getBounds());
+        }
+    }
+
     /** Source of truth for the current bounds of PIP that may be in motion. */
     public static class MotionBoundsState {
         /** The bounds used when PIP is in motion (e.g. during a drag or animation) */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 36dc4e4..fa31a0a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -566,6 +566,8 @@
         mInSwipePipToHomeTransition = false;
         mPictureInPictureParams = null;
         mState = State.UNDEFINED;
+        // Re-set the PIP bounds to none.
+        mPipBoundsState.setBounds(new Rect());
         mPipUiEventLoggerLogger.setTaskInfo(null);
         mPipMenuController.detach();
 
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 9a584c6..debdceb 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
@@ -21,8 +21,10 @@
 import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
 import static android.view.WindowManager.INPUT_CONSUMER_PIP;
 
+import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
 import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection;
 
+import android.Manifest;
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
 import android.app.PictureInPictureParams;
@@ -33,6 +35,7 @@
 import android.content.pm.ParceledListSlice;
 import android.content.res.Configuration;
 import android.graphics.Rect;
+import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -44,6 +47,7 @@
 import android.view.WindowManagerGlobal;
 import android.window.WindowContainerTransaction;
 
+import androidx.annotation.BinderThread;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
@@ -51,9 +55,13 @@
 import com.android.wm.shell.common.DisplayChangeController;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.ExecutorUtils;
+import com.android.wm.shell.common.RemoteCallable;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.TaskStackListenerCallback;
 import com.android.wm.shell.common.TaskStackListenerImpl;
+import com.android.wm.shell.pip.IPip;
+import com.android.wm.shell.pip.IPipAnimationListener;
 import com.android.wm.shell.pip.PinnedStackListenerForwarder;
 import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.pip.PipBoundsAlgorithm;
@@ -71,7 +79,8 @@
 /**
  * Manages the picture-in-picture (PIP) UI and states for Phones.
  */
-public class PipController implements PipTransitionController.PipTransitionCallback {
+public class PipController implements PipTransitionController.PipTransitionCallback,
+        RemoteCallable<PipController> {
     private static final String TAG = "PipController";
 
     private Context mContext;
@@ -85,12 +94,12 @@
     private PipBoundsState mPipBoundsState;
     private PipTouchHandler mTouchHandler;
     private PipTransitionController mPipTransitionController;
-    protected final PipImpl mImpl = new PipImpl();
+    protected final PipImpl mImpl;
 
     private final Rect mTmpInsetBounds = new Rect();
 
     private boolean mIsInFixedRotation;
-    private Consumer<Boolean> mPinnedStackAnimationRecentsCallback;
+    private IPipAnimationListener mPinnedStackAnimationRecentsCallback;
 
     protected PhonePipMenuController mMenuController;
     protected PipTaskOrganizer mPipTaskOrganizer;
@@ -264,6 +273,7 @@
         }
 
         mContext = context;
+        mImpl = new PipImpl();
         mWindowManagerShellWrapper = windowManagerShellWrapper;
         mDisplayController = displayController;
         mPipBoundsAlgorithm = pipBoundsAlgorithm;
@@ -366,6 +376,16 @@
                 });
     }
 
+    @Override
+    public Context getContext() {
+        return mContext;
+    }
+
+    @Override
+    public ShellExecutor getRemoteCallExecutor() {
+        return mMainExecutor;
+    }
+
     private void onConfigurationChanged(Configuration newConfig) {
         mPipBoundsAlgorithm.onConfigurationChanged(mContext);
         mTouchHandler.onConfigurationChanged();
@@ -474,7 +494,7 @@
         mPipTaskOrganizer.setOneShotAnimationType(animationType);
     }
 
-    private void setPinnedStackAnimationListener(Consumer<Boolean> callback) {
+    private void setPinnedStackAnimationListener(IPipAnimationListener callback) {
         mPinnedStackAnimationRecentsCallback = callback;
     }
 
@@ -494,15 +514,6 @@
         mPipTaskOrganizer.stopSwipePipToHome(componentName, destinationBounds);
     }
 
-    /**
-     * Set a listener to watch out for PiP bounds. This is mostly used by SystemUI's
-     * Back-gesture handler, to avoid conflicting with PiP when it's stashed.
-     */
-    private void setPipExclusionBoundsChangeListener(
-            Consumer<Rect> pipExclusionBoundsChangeListener) {
-        mTouchHandler.setPipExclusionBoundsChangeListener(pipExclusionBoundsChangeListener);
-    }
-
     @Override
     public void onPipTransitionStarted(int direction, Rect pipBounds) {
         if (isOutPipDirection(direction)) {
@@ -512,7 +523,11 @@
         // Disable touches while the animation is running
         mTouchHandler.setTouchEnabled(false);
         if (mPinnedStackAnimationRecentsCallback != null) {
-            mPinnedStackAnimationRecentsCallback.accept(true);
+            try {
+                mPinnedStackAnimationRecentsCallback.onPipAnimationStarted();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to call onPinnedStackAnimationStarted()", e);
+            }
         }
     }
 
@@ -638,7 +653,21 @@
         mPipInputConsumer.dump(pw, innerPrefix);
     }
 
+    /**
+     * The interface for calls from outside the Shell, within the host process.
+     */
     private class PipImpl implements Pip {
+        private IPipImpl mIPip;
+
+        @Override
+        public IPip createExternalInterface() {
+            if (mIPip != null) {
+                mIPip.invalidate();
+            }
+            mIPip = new IPipImpl(PipController.this);
+            return mIPip;
+        }
+
         @Override
         public void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) {
             mMainExecutor.execute(() -> {
@@ -696,13 +725,6 @@
         }
 
         @Override
-        public void setPinnedStackAnimationListener(Consumer<Boolean> callback) {
-            mMainExecutor.execute(() -> {
-                PipController.this.setPinnedStackAnimationListener(callback);
-            });
-        }
-
-        @Override
         public void setPinnedStackAnimationType(int animationType) {
             mMainExecutor.execute(() -> {
                 PipController.this.setPinnedStackAnimationType(animationType);
@@ -712,7 +734,7 @@
         @Override
         public void setPipExclusionBoundsChangeListener(Consumer<Rect> listener) {
             mMainExecutor.execute(() -> {
-                PipController.this.setPipExclusionBoundsChangeListener(listener);
+                mPipBoundsState.setPipExclusionBoundsChangeCallback(listener);
             });
         }
 
@@ -724,29 +746,6 @@
         }
 
         @Override
-        public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
-                PictureInPictureParams pictureInPictureParams, int launcherRotation,
-                int shelfHeight) {
-            Rect[] result = new Rect[1];
-            try {
-                mMainExecutor.executeBlocking(() -> {
-                    result[0] = PipController.this.startSwipePipToHome(componentName, activityInfo,
-                            pictureInPictureParams, launcherRotation, shelfHeight);
-                });
-            } catch (InterruptedException e) {
-                Slog.e(TAG, "Failed to start swipe pip to home");
-            }
-            return result[0];
-        }
-
-        @Override
-        public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) {
-            mMainExecutor.execute(() -> {
-                PipController.this.stopSwipePipToHome(componentName, destinationBounds);
-            });
-        }
-
-        @Override
         public void dump(PrintWriter pw) {
             try {
                 mMainExecutor.executeBlocking(() -> {
@@ -757,4 +756,89 @@
             }
         }
     }
+
+    /**
+     * The interface for calls from outside the host process.
+     */
+    @BinderThread
+    private static class IPipImpl extends IPip.Stub {
+        private PipController mController;
+        private IPipAnimationListener mListener;
+        private final IBinder.DeathRecipient mListenerDeathRecipient =
+                new IBinder.DeathRecipient() {
+                    @Override
+                    @BinderThread
+                    public void binderDied() {
+                        final PipController controller = mController;
+                        controller.getRemoteCallExecutor().execute(() -> {
+                            mListener = null;
+                            controller.setPinnedStackAnimationListener(null);
+                        });
+                    }
+                };
+
+        IPipImpl(PipController controller) {
+            mController = controller;
+        }
+
+        /**
+         * Invalidates this instance, preventing future calls from updating the controller.
+         */
+        void invalidate() {
+            mController = null;
+        }
+
+        @Override
+        public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
+                PictureInPictureParams pictureInPictureParams, int launcherRotation,
+                int shelfHeight) {
+            Rect[] result = new Rect[1];
+            executeRemoteCallWithTaskPermission(mController, "startSwipePipToHome",
+                    (controller) -> {
+                        result[0] = controller.startSwipePipToHome(componentName, activityInfo,
+                                pictureInPictureParams, launcherRotation, shelfHeight);
+                    }, true /* blocking */);
+            return result[0];
+        }
+
+        @Override
+        public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) {
+            executeRemoteCallWithTaskPermission(mController, "stopSwipePipToHome",
+                    (controller) -> {
+                        controller.stopSwipePipToHome(componentName, destinationBounds);
+                    });
+        }
+
+        @Override
+        public void setShelfHeight(boolean visible, int height) {
+            executeRemoteCallWithTaskPermission(mController, "setShelfHeight",
+                    (controller) -> {
+                        controller.setShelfHeight(visible, height);
+                    });
+        }
+
+        @Override
+        public void setPinnedStackAnimationListener(IPipAnimationListener listener) {
+            executeRemoteCallWithTaskPermission(mController, "setPinnedStackAnimationListener",
+                    (controller) -> {
+                        if (mListener != null) {
+                            // Reset the old death recipient
+                            mListener.asBinder().unlinkToDeath(mListenerDeathRecipient,
+                                    0 /* flags */);
+                        }
+                        if (listener != null) {
+                            // Register the death recipient for the new listener to clear the listener
+                            try {
+                                listener.asBinder().linkToDeath(mListenerDeathRecipient,
+                                        0 /* flags */);
+                            } catch (RemoteException e) {
+                                Slog.e(TAG, "Failed to link to death");
+                                return;
+                            }
+                        }
+                        mListener = listener;
+                        controller.setPinnedStackAnimationListener(listener);
+                    });
+        }
+    }
 }
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 81a7ae1..402846f 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
@@ -29,7 +29,6 @@
 import android.util.Log;
 import android.view.Choreographer;
 
-import androidx.annotation.VisibleForTesting;
 import androidx.dynamicanimation.animation.AnimationHandler;
 import androidx.dynamicanimation.animation.AnimationHandler.FrameCallbackScheduler;
 import androidx.dynamicanimation.animation.SpringForce;
@@ -489,8 +488,7 @@
     /**
      * Animates the PiP to offset it from the IME or shelf.
      */
-    @VisibleForTesting
-    public void animateToOffset(Rect originalBounds, int offset) {
+    void animateToOffset(Rect originalBounds, int offset) {
         if (DEBUG) {
             Log.d(TAG, "animateToOffset: originalBounds=" + originalBounds + " offset=" + offset
                     + " callers=\n" + Debug.getCallers(5, "    "));
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 44e2624..b0a7319 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
@@ -57,8 +57,6 @@
 import com.android.wm.shell.pip.PipUiEventLogger;
 
 import java.io.PrintWriter;
-import java.lang.ref.WeakReference;
-import java.util.function.Consumer;
 
 /**
  * Manages all the touch handling for PIP on the Phone, including moving, dismissing and expanding
@@ -73,7 +71,6 @@
     // Allow PIP to resize to a slightly bigger state upon touch
     private boolean mEnableResize;
     private final Context mContext;
-    private final PipTaskOrganizer mPipTaskOrganizer;
     private final PipBoundsAlgorithm mPipBoundsAlgorithm;
     private final @NonNull PipBoundsState mPipBoundsState;
     private final PipUiEventLogger mPipUiEventLogger;
@@ -81,7 +78,6 @@
     private final ShellExecutor mMainExecutor;
 
     private PipResizeGestureHandler mPipResizeGestureHandler;
-    private WeakReference<Consumer<Rect>> mPipExclusionBoundsChangeListener;
 
     private final PhonePipMenuController mMenuController;
     private final AccessibilityManager mAccessibilityManager;
@@ -170,7 +166,6 @@
         mContext = context;
         mMainExecutor = mainExecutor;
         mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
-        mPipTaskOrganizer = pipTaskOrganizer;
         mPipBoundsAlgorithm = pipBoundsAlgorithm;
         mPipBoundsState = pipBoundsState;
         mMenuController = menuController;
@@ -290,11 +285,6 @@
 
             mFloatingContentCoordinator.onContentRemoved(mMotionHelper);
         }
-        // Reset exclusion to none.
-        if (mPipExclusionBoundsChangeListener != null
-                && mPipExclusionBoundsChangeListener.get() != null) {
-            mPipExclusionBoundsChangeListener.get().accept(new Rect());
-        }
         mPipResizeGestureHandler.onActivityUnpinned();
     }
 
@@ -931,10 +921,6 @@
         }
 
         private void stashEndAction() {
-            if (mPipExclusionBoundsChangeListener != null
-                    && mPipExclusionBoundsChangeListener.get() != null) {
-                mPipExclusionBoundsChangeListener.get().accept(mPipBoundsState.getBounds());
-            }
             if (mPipBoundsState.getBounds().left < 0
                     && mPipBoundsState.getStashedState() != STASH_TYPE_LEFT) {
                 mPipUiEventLogger.log(
@@ -954,11 +940,6 @@
                 // dismiss overlay, so just finish it after the animation completes
                 mMenuController.hideMenu();
             }
-            // Reset exclusion to none.
-            if (mPipExclusionBoundsChangeListener != null
-                    && mPipExclusionBoundsChangeListener.get() != null) {
-                mPipExclusionBoundsChangeListener.get().accept(new Rect());
-            }
         }
 
         private boolean shouldStash(PointF vel, Rect motionBounds) {
@@ -982,13 +963,6 @@
         }
     }
 
-    void setPipExclusionBoundsChangeListener(Consumer<Rect> pipExclusionBoundsChangeListener) {
-        mPipExclusionBoundsChangeListener = new WeakReference<>(pipExclusionBoundsChangeListener);
-        pipExclusionBoundsChangeListener.accept(mPipTaskOrganizer.isInPip()
-                ? mPipBoundsState.getBounds() : new Rect());
-
-    }
-
     /**
      * Updates the current movement bounds based on whether the menu is currently visible and
      * resized.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
index 2b0a0cd..963a3dc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
@@ -28,7 +28,7 @@
     // with those in the framework ProtoLogGroup
     WM_SHELL_TASK_ORG(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
             Consts.TAG_WM_SHELL),
-    WM_SHELL_TRANSITIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+    WM_SHELL_TRANSITIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
             Consts.TAG_WM_SHELL),
     WM_SHELL_DRAG_AND_DROP(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
             Consts.TAG_WM_SHELL),
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
new file mode 100644
index 0000000..0c46eab
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
@@ -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.wm.shell.splitscreen;
+
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.UserHandle;
+
+import com.android.wm.shell.splitscreen.ISplitScreenListener;
+
+/**
+ * Interface that is exposed to remote callers to manipulate the splitscreen feature.
+ */
+interface ISplitScreen {
+
+    /**
+     * Registers a split screen listener.
+     */
+    oneway void registerSplitScreenListener(in ISplitScreenListener listener) = 1;
+
+    /**
+     * Unregisters a split screen listener.
+     */
+    oneway void unregisterSplitScreenListener(in ISplitScreenListener listener) = 2;
+
+    /**
+     * Hides the side-stage if it is currently visible.
+     */
+    oneway void setSideStageVisibility(boolean visible) = 3;
+
+    /**
+     * Removes a task from the side stage.
+     */
+    oneway void removeFromSideStage(int taskId) = 4;
+
+    /**
+     * Removes the split-screen stages.
+     */
+    oneway void exitSplitScreen() = 5;
+
+    /**
+     * @param exitSplitScreenOnHide if to exit split-screen if both stages are not visible.
+     */
+    oneway void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) = 6;
+
+    /**
+     * Starts a task in a stage.
+     */
+    oneway void startTask(int taskId, int stage, int position, in Bundle options) = 7;
+
+    /**
+     * Starts a shortcut in a stage.
+     */
+    oneway void startShortcut(String packageName, String shortcutId, int stage, int position,
+            in Bundle options, in UserHandle user) = 8;
+
+    /**
+     * Starts an activity in a stage.
+     */
+    oneway void startIntent(in PendingIntent intent, in Intent fillInIntent, int stage,
+            int position, in Bundle options) = 9;
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreenListener.aidl
similarity index 83%
rename from packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl
rename to libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreenListener.aidl
index 54242be..faab4c2 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreenListener.aidl
@@ -14,12 +14,20 @@
  * limitations under the License.
  */
 
-package com.android.systemui.shared.recents;
+package com.android.wm.shell.splitscreen;
 
 /**
  * Listener interface that Launcher attaches to SystemUI to get split-screen callbacks.
  */
 oneway interface ISplitScreenListener {
+
+    /**
+     * Called when the stage position changes.
+     */
     void onStagePositionChanged(int stage, int position);
+
+    /**
+     * Called when a task changes stages.
+     */
     void onTaskStageChanged(int taskId, int stage, boolean visible);
-}
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
index 25a84bd..340b55d7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -35,7 +35,7 @@
  * TODO: Figure out which of these are actually needed outside of the Shell
  */
 @ExternalThread
-public interface SplitScreen extends DragAndDropPolicy.Starter {
+public interface SplitScreen {
     /**
      * Stage position isn't specified normally meaning to use what ever it is currently set to.
      */
@@ -89,35 +89,10 @@
         void onTaskStageChanged(int taskId, @StageType int stage, boolean visible);
     }
 
-    /** @return {@code true} if split-screen is currently visible. */
-    boolean isSplitScreenVisible();
-    /** Moves a task in the side-stage of split-screen. */
-    boolean moveToSideStage(int taskId, @StagePosition int sideStagePosition);
-    /** Moves a task in the side-stage of split-screen. */
-    boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
-            @StagePosition int sideStagePosition);
-    /** Removes a task from the side-stage of split-screen. */
-    boolean removeFromSideStage(int taskId);
-    /** Sets the position of the side-stage. */
-    void setSideStagePosition(@StagePosition int sideStagePosition);
-    /** Hides the side-stage if it is currently visible. */
-    void setSideStageVisibility(boolean visible);
-
-    /** Removes the split-screen stages. */
-    void exitSplitScreen();
-    /** @param exitSplitScreenOnHide if to exit split-screen if both stages are not visible. */
-    void exitSplitScreenOnHide(boolean exitSplitScreenOnHide);
-    /** Gets the stage bounds. */
-    void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds);
-
-    void registerSplitScreenListener(SplitScreenListener listener);
-    void unregisterSplitScreenListener(SplitScreenListener listener);
-
-    void startTask(int taskId,
-            @StageType int stage, @StagePosition int position, @Nullable Bundle options);
-    void startShortcut(String packageName, String shortcutId, @StageType int stage,
-            @StagePosition int position, @Nullable Bundle options, UserHandle user);
-    void startIntent(PendingIntent intent, Context context,
-            @Nullable Intent fillInIntent, @StageType int stage,
-            @StagePosition int position, @Nullable Bundle options);
+    /**
+     * Returns a binder that can be passed to an external process to manipulate SplitScreen.
+     */
+    default ISplitScreen createExternalInterface() {
+        return null;
+    }
 }
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 bb6f6f2..d4362ef 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
@@ -18,6 +18,7 @@
 
 import static android.view.Display.DEFAULT_DISPLAY;
 
+import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
 import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_TOP_OR_LEFT;
 import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_UNDEFINED;
@@ -34,19 +35,24 @@
 import android.content.pm.LauncherApps;
 import android.graphics.Rect;
 import android.os.Bundle;
+import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.Slog;
 
+import androidx.annotation.BinderThread;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 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.RemoteCallable;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.common.annotations.ExternalThread;
 import com.android.wm.shell.draganddrop.DragAndDropPolicy;
+import com.android.wm.shell.splitscreen.ISplitScreenListener;
 
 import java.io.PrintWriter;
 
@@ -55,7 +61,8 @@
  * {@link SplitScreen}.
  * @see StageCoordinator
  */
-public class SplitScreenController implements DragAndDropPolicy.Starter {
+public class SplitScreenController implements DragAndDropPolicy.Starter,
+        RemoteCallable<SplitScreenController> {
     private static final String TAG = SplitScreenController.class.getSimpleName();
 
     private final ShellTaskOrganizer mTaskOrganizer;
@@ -84,6 +91,16 @@
         return mImpl;
     }
 
+    @Override
+    public Context getContext() {
+        return mContext;
+    }
+
+    @Override
+    public ShellExecutor getRemoteCallExecutor() {
+        return mMainExecutor;
+    }
+
     public void onOrganizerRegistered() {
         if (mStageCoordinator == null) {
             // TODO: Multi-display
@@ -172,13 +189,13 @@
         }
     }
 
-    public void startIntent(PendingIntent intent, Context context,
-            Intent fillInIntent, @SplitScreen.StageType int stage,
-            @SplitScreen.StagePosition int position, @Nullable Bundle options) {
+    public void startIntent(PendingIntent intent, Intent fillInIntent,
+            @SplitScreen.StageType int stage, @SplitScreen.StagePosition int position,
+            @Nullable Bundle options) {
         options = resolveStartStage(stage, position, options);
 
         try {
-            intent.send(context, 0, fillInIntent, null, null, null, options);
+            intent.send(mContext, 0, fillInIntent, null, null, null, options);
         } catch (PendingIntent.CanceledException e) {
             Slog.e(TAG, "Failed to launch activity", e);
         }
@@ -242,121 +259,170 @@
         }
     }
 
+    /**
+     * The interface for calls from outside the Shell, within the host process.
+     */
+    @ExternalThread
     private class SplitScreenImpl implements SplitScreen {
+        private ISplitScreenImpl mISplitScreen;
+
         @Override
-        public boolean isSplitScreenVisible() {
-            return mMainExecutor.executeBlockingForResult(() -> {
-                return SplitScreenController.this.isSplitScreenVisible();
-            }, Boolean.class);
+        public ISplitScreen createExternalInterface() {
+            if (mISplitScreen != null) {
+                mISplitScreen.invalidate();
+            }
+            mISplitScreen = new ISplitScreenImpl(SplitScreenController.this);
+            return mISplitScreen;
+        }
+    }
+
+    /**
+     * The interface for calls from outside the host process.
+     */
+    @BinderThread
+    private static class ISplitScreenImpl extends ISplitScreen.Stub {
+        private SplitScreenController mController;
+        private ISplitScreenListener mListener;
+        private final SplitScreen.SplitScreenListener mSplitScreenListener =
+                new SplitScreen.SplitScreenListener() {
+                    @Override
+                    public void onStagePositionChanged(int stage, int position) {
+                        try {
+                            if (mListener != null) {
+                                mListener.onStagePositionChanged(stage, position);
+                            }
+                        } catch (RemoteException e) {
+                            Slog.e(TAG, "onStagePositionChanged", e);
+                        }
+                    }
+
+                    @Override
+                    public void onTaskStageChanged(int taskId, int stage, boolean visible) {
+                        try {
+                            if (mListener != null) {
+                                mListener.onTaskStageChanged(taskId, stage, visible);
+                            }
+                        } catch (RemoteException e) {
+                            Slog.e(TAG, "onTaskStageChanged", e);
+                        }
+                    }
+                };
+        private final IBinder.DeathRecipient mListenerDeathRecipient =
+                new IBinder.DeathRecipient() {
+                    @Override
+                    @BinderThread
+                    public void binderDied() {
+                        final SplitScreenController controller = mController;
+                        controller.getRemoteCallExecutor().execute(() -> {
+                            mListener = null;
+                            controller.unregisterSplitScreenListener(mSplitScreenListener);
+                        });
+                    }
+                };
+
+        public ISplitScreenImpl(SplitScreenController controller) {
+            mController = controller;
+        }
+
+        /**
+         * Invalidates this instance, preventing future calls from updating the controller.
+         */
+        void invalidate() {
+            mController = null;
         }
 
         @Override
-        public boolean moveToSideStage(int taskId, int sideStagePosition) {
-            return mMainExecutor.executeBlockingForResult(() -> {
-                return SplitScreenController.this.moveToSideStage(taskId, sideStagePosition);
-            }, Boolean.class);
+        public void registerSplitScreenListener(ISplitScreenListener listener) {
+            executeRemoteCallWithTaskPermission(mController, "registerSplitScreenListener",
+                    (controller) -> {
+                        if (mListener != null) {
+                            mListener.asBinder().unlinkToDeath(mListenerDeathRecipient,
+                                    0 /* flags */);
+                        }
+                        if (listener != null) {
+                            try {
+                                listener.asBinder().linkToDeath(mListenerDeathRecipient,
+                                        0 /* flags */);
+                            } catch (RemoteException e) {
+                                Slog.e(TAG, "Failed to link to death");
+                                return;
+                            }
+                        }
+                        mListener = listener;
+                        controller.registerSplitScreenListener(mSplitScreenListener);
+                    });
         }
 
         @Override
-        public boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
-                int sideStagePosition) {
-            return mMainExecutor.executeBlockingForResult(() -> {
-                return SplitScreenController.this.moveToSideStage(task, sideStagePosition);
-            }, Boolean.class);
-        }
-
-        @Override
-        public boolean removeFromSideStage(int taskId) {
-            return mMainExecutor.executeBlockingForResult(() -> {
-                return SplitScreenController.this.removeFromSideStage(taskId);
-            }, Boolean.class);
-        }
-
-        @Override
-        public void setSideStagePosition(int sideStagePosition) {
-            mMainExecutor.execute(() -> {
-                SplitScreenController.this.setSideStagePosition(sideStagePosition);
-            });
-        }
-
-        @Override
-        public void setSideStageVisibility(boolean visible) {
-            mMainExecutor.execute(() -> {
-                SplitScreenController.this.setSideStageVisibility(visible);
-            });
-        }
-
-        @Override
-        public void enterSplitScreen(int taskId, boolean leftOrTop) {
-            mMainExecutor.execute(() -> {
-                SplitScreenController.this.enterSplitScreen(taskId, leftOrTop);
-            });
+        public void unregisterSplitScreenListener(ISplitScreenListener listener) {
+            executeRemoteCallWithTaskPermission(mController, "unregisterSplitScreenListener",
+                    (controller) -> {
+                        if (mListener != null) {
+                            mListener.asBinder().unlinkToDeath(mListenerDeathRecipient,
+                                    0 /* flags */);
+                        }
+                        mListener = null;
+                        controller.unregisterSplitScreenListener(mSplitScreenListener);
+                    });
         }
 
         @Override
         public void exitSplitScreen() {
-            mMainExecutor.execute(() -> {
-                SplitScreenController.this.exitSplitScreen();
-            });
+            executeRemoteCallWithTaskPermission(mController, "exitSplitScreen",
+                    (controller) -> {
+                        controller.exitSplitScreen();
+                    });
         }
 
         @Override
         public void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
-            mMainExecutor.execute(() -> {
-                SplitScreenController.this.exitSplitScreenOnHide(exitSplitScreenOnHide);
-            });
+            executeRemoteCallWithTaskPermission(mController, "exitSplitScreenOnHide",
+                    (controller) -> {
+                        controller.exitSplitScreenOnHide(exitSplitScreenOnHide);
+                    });
         }
 
         @Override
-        public void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds) {
-            try {
-                mMainExecutor.executeBlocking(() -> {
-                    SplitScreenController.this.getStageBounds(outTopOrLeftBounds,
-                            outBottomOrRightBounds);
-                });
-            } catch (InterruptedException e) {
-                Slog.e(TAG, "Failed to get stage bounds in 2s");
-            }
+        public void setSideStageVisibility(boolean visible) {
+            executeRemoteCallWithTaskPermission(mController, "setSideStageVisibility",
+                    (controller) -> {
+                        controller.setSideStageVisibility(visible);
+                    });
         }
 
         @Override
-        public void registerSplitScreenListener(SplitScreenListener listener) {
-            mMainExecutor.execute(() -> {
-                SplitScreenController.this.registerSplitScreenListener(listener);
-            });
-        }
-
-        @Override
-        public void unregisterSplitScreenListener(SplitScreenListener listener) {
-            mMainExecutor.execute(() -> {
-                SplitScreenController.this.unregisterSplitScreenListener(listener);
-            });
+        public void removeFromSideStage(int taskId) {
+            executeRemoteCallWithTaskPermission(mController, "removeFromSideStage",
+                    (controller) -> {
+                        controller.removeFromSideStage(taskId);
+                    });
         }
 
         @Override
         public void startTask(int taskId, int stage, int position, @Nullable Bundle options) {
-            mMainExecutor.execute(() -> {
-                SplitScreenController.this.startTask(taskId, stage, position, options);
-            });
+            executeRemoteCallWithTaskPermission(mController, "startTask",
+                    (controller) -> {
+                        controller.startTask(taskId, stage, position, options);
+                    });
         }
 
         @Override
         public void startShortcut(String packageName, String shortcutId, int stage, int position,
                 @Nullable Bundle options, UserHandle user) {
-            mMainExecutor.execute(() -> {
-                SplitScreenController.this.startShortcut(packageName, shortcutId, stage, position,
-                        options, user);
-            });
+            executeRemoteCallWithTaskPermission(mController, "startShortcut",
+                    (controller) -> {
+                        controller.startShortcut(packageName, shortcutId, stage, position,
+                                options, user);
+                    });
         }
 
         @Override
-        public void startIntent(PendingIntent intent, Context context, Intent fillInIntent,
-                int stage, int position, @Nullable Bundle options) {
-            mMainExecutor.execute(() -> {
-                SplitScreenController.this.startIntent(intent, context, fillInIntent, stage,
-                        position, options);
-            });
+        public void startIntent(PendingIntent intent, Intent fillInIntent, int stage, int position,
+                @Nullable Bundle options) {
+            executeRemoteCallWithTaskPermission(mController, "startIntent",
+                    (controller) -> {
+                        controller.startIntent(intent, fillInIntent, stage, position, options);
+                    });
         }
     }
-
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/IStartingWindow.aidl
similarity index 62%
copy from packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl
copy to libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/IStartingWindow.aidl
index 54242be..546c406 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/IStartingWindow.aidl
@@ -14,12 +14,16 @@
  * limitations under the License.
  */
 
-package com.android.systemui.shared.recents;
+package com.android.wm.shell.startingsurface;
+
+import com.android.wm.shell.startingsurface.IStartingWindowListener;
 
 /**
- * Listener interface that Launcher attaches to SystemUI to get split-screen callbacks.
+ * Interface that is exposed to remote callers to manipulate starting windows.
  */
-oneway interface ISplitScreenListener {
-    void onStagePositionChanged(int stage, int position);
-    void onTaskStageChanged(int taskId, int stage, boolean visible);
+interface IStartingWindow {
+    /**
+     * Sets listener to get task launching callbacks.
+     */
+    oneway void setStartingWindowListener(IStartingWindowListener listener) = 43;
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IStartingWindowListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/IStartingWindowListener.aidl
similarity index 90%
rename from packages/SystemUI/shared/src/com/android/systemui/shared/recents/IStartingWindowListener.aidl
rename to libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/IStartingWindowListener.aidl
index eb3e60c..f562c8f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IStartingWindowListener.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/IStartingWindowListener.aidl
@@ -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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.shared.recents;
+package com.android.wm.shell.startingsurface;
 
 /**
  * Listener interface that Launcher attaches to SystemUI to get
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 3f9c271..3f46fee 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
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.startingsurface;
 
+import android.annotation.ColorInt;
 import android.annotation.NonNull;
 import android.app.ActivityThread;
 import android.content.Context;
@@ -149,14 +150,16 @@
                 .setThemeDrawable(themeBGDrawable)
                 .setIconDrawable(iconDrawable)
                 .setIconAnimationDuration(animationDuration)
-                .setBrandingDrawable(attrs.mBrandingImage).build();
+                .setBrandingDrawable(attrs.mBrandingImage)
+                .setIconBackground(attrs.mIconBgColor).build();
     }
 
-    private static class SplashScreenWindowAttrs {
+    static class SplashScreenWindowAttrs {
         private int mWindowBgResId = 0;
         private int mWindowBgColor = Color.TRANSPARENT;
         private Drawable mReplaceIcon = null;
         private Drawable mBrandingImage = null;
+        private int mIconBgColor = Color.TRANSPARENT;
         private int mAnimationDuration = 0;
 
         static SplashScreenWindowAttrs createWindowAttrs(Context context) {
@@ -172,6 +175,8 @@
                     R.styleable.Window_windowSplashScreenAnimationDuration, 0);
             attrs.mBrandingImage = typedArray.getDrawable(
                     R.styleable.Window_windowSplashScreenBrandingImage);
+            attrs.mIconBgColor = typedArray.getColor(
+                    R.styleable.Window_windowSplashScreenIconBackgroundColor, Color.TRANSPARENT);
             typedArray.recycle();
             if (DEBUG) {
                 Slog.d(TAG, "window attributes color: "
@@ -189,6 +194,7 @@
         private int mIconAnimationDuration;
         private Context mContext;
         private Drawable mBrandingDrawable;
+        private @ColorInt int mIconBackground;
 
         // result
         private boolean mBuildComplete = false;
@@ -221,6 +227,12 @@
             return this;
         }
 
+        StartingWindowViewBuilder setIconBackground(int color) {
+            mIconBackground = color;
+            mBuildComplete = false;
+            return this;
+        }
+
         StartingWindowViewBuilder setContext(Context context) {
             mContext = context;
             mBuildComplete = false;
@@ -244,7 +256,9 @@
                 if (DEBUG) {
                     Slog.d(TAG, "The icon is not an AdaptiveIconDrawable");
                 }
-                mFinalIconDrawable = mIconDrawable;
+                mFinalIconDrawable = SplashscreenIconDrawableFactory.makeIconDrawable(
+                        mIconBackground != Color.TRANSPARENT
+                        ? mIconBackground : mThemeColor, mIconDrawable);
             }
             final int iconSize = mFinalIconDrawable != null ? (int) (mIconSize * mScale) : 0;
             mCachedResult = fillViewWithIcon(mContext, iconSize, mFinalIconDrawable);
@@ -252,6 +266,12 @@
             return mCachedResult;
         }
 
+        private void createIconDrawable(Drawable iconDrawable) {
+            mFinalIconDrawable = SplashscreenIconDrawableFactory.makeIconDrawable(
+                    mIconBackground != Color.TRANSPARENT
+                    ? mIconBackground : mThemeColor, iconDrawable);
+        }
+
         private void processThemeColor() {
             final DrawableColorTester themeBGTester =
                     new DrawableColorTester(mThemeBGDrawable, true /* filterTransparent */);
@@ -307,8 +327,7 @@
                 }
                 // Using AdaptiveIconDrawable here can help keep the shape consistent with the
                 // current settings.
-                mFinalIconDrawable = new AdaptiveIconDrawable(
-                        new ColorDrawable(mThemeColor), iconForeground);
+                createIconDrawable(iconForeground);
                 // Reference AdaptiveIcon description, outer is 108 and inner is 72, so we
                 // should enlarge the size 108/72 if we only draw adaptiveIcon's foreground.
                 if (foreIconTester.nonTransparentRatio() < ENLARGE_FOREGROUND_ICON_THRESHOLD) {
@@ -318,7 +337,11 @@
                 if (DEBUG) {
                     Slog.d(TAG, "makeSplashScreenContentView: draw whole icon");
                 }
-                mFinalIconDrawable = adaptiveIconDrawable;
+                if (mIconBackground != Color.TRANSPARENT) {
+                    createIconDrawable(adaptiveIconDrawable);
+                } else {
+                    mFinalIconDrawable = adaptiveIconDrawable;
+                }
             }
             return true;
         }
@@ -326,7 +349,8 @@
         private SplashScreenView fillViewWithIcon(Context context,
                 int iconSize, Drawable iconDrawable) {
             final SplashScreenView.Builder builder = new SplashScreenView.Builder(context);
-            builder.setIconSize(iconSize).setBackgroundColor(mThemeColor);
+            builder.setIconSize(iconSize).setBackgroundColor(mThemeColor)
+                    .setIconBackground(mIconBackground);
             if (iconDrawable != null) {
                 builder.setCenterViewDrawable(iconDrawable);
             }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
new file mode 100644
index 0000000..8626dbc
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
@@ -0,0 +1,217 @@
+/*
+ * 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.animation.Animator;
+import android.animation.ValueAnimator;
+import android.annotation.ColorInt;
+import android.annotation.NonNull;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.Animatable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.SystemClock;
+import android.util.PathParser;
+import android.window.SplashScreenView;
+
+import com.android.internal.R;
+
+import java.util.function.Consumer;
+
+/**
+ * Creating a lightweight Drawable object used for splash screen.
+ * @hide
+ */
+public class SplashscreenIconDrawableFactory {
+
+    static Drawable makeIconDrawable(@ColorInt int backgroundColor,
+            @NonNull Drawable foregroundDrawable) {
+        if (foregroundDrawable instanceof Animatable) {
+            return new AnimatableIconDrawable(backgroundColor, foregroundDrawable);
+        } else {
+            // TODO make a light weight drawable instead of AdaptiveIconDrawable
+            return new AdaptiveIconDrawable(new ColorDrawable(backgroundColor), foregroundDrawable);
+        }
+    }
+
+    /**
+     * A lightweight AdaptiveIconDrawable which support foreground to be Animatable, and keep this
+     * drawable masked by config_icon_mask.
+     * @hide
+     */
+    private static class AnimatableIconDrawable extends SplashScreenView.SplashscreenIconDrawable {
+        private static final float MASK_SIZE = AdaptiveIconDrawable.MASK_SIZE;
+        private static final float EXTRA_INSET_PERCENTAGE = 1 / 4f;
+        private static final float DEFAULT_VIEW_PORT_SCALE = 1f / (1 + 2 * EXTRA_INSET_PERCENTAGE);
+        private final Rect mTmpOutRect = new Rect();
+        /**
+         * Clip path defined in R.string.config_icon_mask.
+         */
+        private static Path sMask;
+
+        /**
+         * Scaled mask based on the view bounds.
+         */
+        private final Path mMask;
+        private final Path mMaskScaleOnly;
+        private final Matrix mMaskMatrix;
+        private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        private final Drawable mForegroundDrawable;
+        private Animatable mAnimatableIcon;
+        private Animator mIconAnimator;
+        private boolean mAnimationTriggered;
+        private long mIconAnimationStart;
+
+        AnimatableIconDrawable(@ColorInt int backgroundColor, Drawable foregroundDrawable) {
+            mForegroundDrawable = foregroundDrawable;
+            final Resources r = Resources.getSystem();
+            sMask = PathParser.createPathFromPathData(r.getString(R.string.config_icon_mask));
+            mMask = new Path(sMask);
+            mMaskScaleOnly = new Path(mMask);
+            mMaskMatrix = new Matrix();
+            mPaint.setColor(backgroundColor);
+            mPaint.setStyle(Paint.Style.FILL);
+            if (mForegroundDrawable != null) {
+                mForegroundDrawable.setCallback(mCallback);
+            }
+        }
+
+        @Override
+        protected boolean prepareAnimate(long duration, Consumer<Long> startListener) {
+            mAnimatableIcon = (Animatable) mForegroundDrawable;
+            mIconAnimator = ValueAnimator.ofInt(0, 1);
+            mIconAnimator.setDuration(duration);
+            mIconAnimator.addListener(new Animator.AnimatorListener() {
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    mIconAnimationStart = SystemClock.uptimeMillis();
+                    if (startListener != null) {
+                        startListener.accept(mIconAnimationStart);
+                    }
+                    mAnimatableIcon.start();
+                }
+
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mAnimatableIcon.stop();
+                }
+
+                @Override
+                public void onAnimationCancel(Animator animation) {
+                    mAnimatableIcon.stop();
+                }
+
+                @Override
+                public void onAnimationRepeat(Animator animation) {
+                    // do not repeat
+                    mAnimatableIcon.stop();
+                }
+            });
+            return true;
+        }
+
+        @Override
+        protected void onBoundsChange(Rect bounds) {
+            if (bounds.isEmpty()) {
+                return;
+            }
+            updateLayerBounds(bounds);
+        }
+
+        private final Callback mCallback = new Callback() {
+            @Override
+            public void invalidateDrawable(@NonNull Drawable who) {
+                invalidateSelf();
+            }
+
+            @Override
+            public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) {
+                scheduleSelf(what, when);
+            }
+
+            @Override
+            public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) {
+                unscheduleSelf(what);
+            }
+        };
+
+        private void updateLayerBounds(Rect bounds) {
+            int cX = bounds.width() / 2;
+            int cY = bounds.height() / 2;
+
+            int insetWidth = (int) (bounds.width() / (DEFAULT_VIEW_PORT_SCALE * 2));
+            int insetHeight = (int) (bounds.height() / (DEFAULT_VIEW_PORT_SCALE * 2));
+            final Rect outRect = mTmpOutRect;
+            outRect.set(cX - insetWidth, cY - insetHeight, cX + insetWidth, cY + insetHeight);
+
+            if (mForegroundDrawable != null) {
+                mForegroundDrawable.setBounds(outRect);
+            }
+            // reset everything that depends on the view bounds
+            mMaskMatrix.setScale(bounds.width() / MASK_SIZE, bounds.height() / MASK_SIZE);
+            sMask.transform(mMaskMatrix, mMaskScaleOnly);
+            invalidateSelf();
+        }
+
+        private void ensureAnimationStarted() {
+            if (mAnimationTriggered) {
+                return;
+            }
+            if (mIconAnimator != null && !mIconAnimator.isRunning()) {
+                mIconAnimator.start();
+            }
+            mAnimationTriggered = true;
+        }
+
+        @Override
+        public void draw(Canvas canvas) {
+            if (mMaskScaleOnly != null) {
+                canvas.drawPath(mMaskScaleOnly, mPaint);
+            }
+            if (mForegroundDrawable != null) {
+                ensureAnimationStarted();
+                mForegroundDrawable.draw(canvas);
+            }
+        }
+
+        @Override
+        public void setAlpha(int alpha) {
+            mPaint.setAlpha(alpha);
+        }
+
+        @Override
+        public void setColorFilter(ColorFilter colorFilter) {
+            if (mForegroundDrawable != null) {
+                mForegroundDrawable.setColorFilter(colorFilter);
+            }
+        }
+
+        @Override
+        public int getOpacity() {
+            return PixelFormat.TRANSLUCENT;
+        }
+    }
+
+}
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
index f258286..079d689 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
@@ -16,35 +16,15 @@
 
 package com.android.wm.shell.startingsurface;
 
-import android.graphics.Rect;
-import android.os.IBinder;
-import android.view.SurfaceControl;
-import android.window.StartingWindowInfo;
-
-import java.util.function.BiConsumer;
 /**
  * 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, SurfaceControl leash, Rect frame,
-            boolean playRevealAnimation);
-    /**
-     * Called when the Task wants to copy the splash screen.
-     * @param taskId
-     */
-    void copySplashScreenView(int taskId);
 
     /**
-     * Registers the starting window listener.
-     *
-     * @param listener The callback when need a starting window.
+     * Returns a binder that can be passed to an external process to manipulate starting windows.
      */
-    void setStartingWindowListener(BiConsumer<Integer, Integer> listener);
+    default IStartingWindow createExternalInterface() {
+        return null;
+    }
 }
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 50d8098..b592121 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
@@ -69,9 +69,6 @@
     private final ShellExecutor mSplashScreenExecutor;
     private final SplashscreenContentDrawer mSplashscreenContentDrawer;
 
-    // TODO(b/131727939) remove this when clearing ActivityRecord
-    private static final int REMOVE_WHEN_TIMEOUT = 2000;
-
     public StartingSurfaceDrawer(Context context, ShellExecutor splashScreenExecutor,
             TransactionPool pool) {
         mContext = context;
@@ -295,12 +292,8 @@
             TaskSnapshot snapshot) {
         final int taskId = startingWindowInfo.taskInfo.taskId;
         final TaskSnapshotWindow surface = TaskSnapshotWindow.create(startingWindowInfo, appToken,
-                snapshot, mSplashScreenExecutor,
-                () -> removeWindowNoAnimate(taskId));
-        mSplashScreenExecutor.executeDelayed(() -> removeWindowNoAnimate(taskId),
-                REMOVE_WHEN_TIMEOUT);
-        final StartingWindowRecord tView =
-                new StartingWindowRecord(null/* decorView */, surface);
+                snapshot, mSplashScreenExecutor, () -> removeWindowNoAnimate(taskId));
+        final StartingWindowRecord tView = new StartingWindowRecord(null/* decorView */, surface);
         mStartingWindowRecords.put(taskId, tView);
     }
 
@@ -354,8 +347,6 @@
         }
         if (shouldSaveView) {
             removeWindowNoAnimate(taskId);
-            mSplashScreenExecutor.executeDelayed(
-                    () -> removeWindowNoAnimate(taskId), REMOVE_WHEN_TIMEOUT);
             saveSplashScreenRecord(taskId, view);
         }
         return shouldSaveView;
@@ -371,7 +362,6 @@
         final StartingWindowRecord record = mStartingWindowRecords.get(taskId);
         if (record != null) {
             record.setSplashScreenView(splashScreenView);
-            splashScreenView.startIntroAnimation();
         }
     }
 
@@ -392,7 +382,6 @@
                     if (leash != null || playRevealAnimation) {
                         mSplashscreenContentDrawer.applyExitAnimation(record.mContentView,
                                 leash, frame, record.isEarlyExit(), exitFinish);
-                        mSplashScreenExecutor.executeDelayed(exitFinish, REMOVE_WHEN_TIMEOUT);
                     } else {
                         // the SplashScreenView has been copied to client, skip default exit
                         // animation
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
index a694e52..a06068d6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
@@ -25,6 +25,8 @@
 import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING;
 import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH;
 
+import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
+
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityTaskManager;
 import android.content.Context;
@@ -37,6 +39,9 @@
 import android.window.TaskOrganizer;
 import android.window.TaskSnapshot;
 
+import androidx.annotation.BinderThread;
+
+import com.android.wm.shell.common.RemoteCallable;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.TransactionPool;
 
@@ -58,7 +63,7 @@
  * constructor to keep everything synchronized.
  * @hide
  */
-public class StartingWindowController {
+public class StartingWindowController implements RemoteCallable<StartingWindowController> {
     private static final String TAG = StartingWindowController.class.getSimpleName();
     static final boolean DEBUG_SPLASH_SCREEN = false;
     static final boolean DEBUG_TASK_SNAPSHOT = false;
@@ -68,17 +73,17 @@
 
     private BiConsumer<Integer, Integer> mTaskLaunchingCallback;
     private final StartingSurfaceImpl mImpl = new StartingSurfaceImpl();
+    private final Context mContext;
     private final ShellExecutor mSplashScreenExecutor;
 
     // For Car Launcher
     public StartingWindowController(Context context, ShellExecutor splashScreenExecutor) {
-        mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, splashScreenExecutor,
-                new TransactionPool());
-        mSplashScreenExecutor = splashScreenExecutor;
+        this(context, splashScreenExecutor, new TransactionPool());
     }
 
     public StartingWindowController(Context context, ShellExecutor splashScreenExecutor,
             TransactionPool pool) {
+        mContext = context;
         mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, splashScreenExecutor, pool);
         mSplashScreenExecutor = splashScreenExecutor;
     }
@@ -90,6 +95,16 @@
         return mImpl;
     }
 
+    @Override
+    public Context getContext() {
+        return mContext;
+    }
+
+    @Override
+    public ShellExecutor getRemoteCallExecutor() {
+        return mSplashScreenExecutor;
+    }
+
     private static class StartingTypeChecker {
         TaskSnapshot mSnapshot;
 
@@ -150,6 +165,13 @@
                 }
                 return false;
             }
+            if (!snapshot.getTopActivityComponent().equals(windowInfo.taskInfo.topActivity)) {
+                if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
+                    Slog.d(TAG, "isSnapshotCompatible obsoleted snapshot "
+                            + windowInfo.taskInfo.topActivity);
+                }
+                return false;
+            }
 
             final int taskRotation = windowInfo.taskInfo.configuration
                     .windowConfiguration.getRotation();
@@ -188,59 +210,121 @@
     /**
      * Called when a task need a starting window.
      */
-    void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
-        final int suggestionType = mStartingTypeChecker.estimateStartingWindowType(windowInfo);
-        final RunningTaskInfo runningTaskInfo = windowInfo.taskInfo;
-        if (mTaskLaunchingCallback != null) {
-            mTaskLaunchingCallback.accept(runningTaskInfo.taskId, suggestionType);
-        }
-        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!
+    public void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
+        mSplashScreenExecutor.execute(() -> {
+            final int suggestionType = mStartingTypeChecker.estimateStartingWindowType(windowInfo);
+            final RunningTaskInfo runningTaskInfo = windowInfo.taskInfo;
+            if (mTaskLaunchingCallback != null) {
+                mTaskLaunchingCallback.accept(runningTaskInfo.taskId, suggestionType);
+            }
+            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);
+    public void copySplashScreenView(int taskId) {
+        mSplashScreenExecutor.execute(() -> {
+            mStartingSurfaceDrawer.copySplashScreenView(taskId);
+        });
     }
 
     /**
      * Called when the content of a task is ready to show, starting window can be removed.
      */
-    void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+    public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
             boolean playRevealAnimation) {
-        mStartingSurfaceDrawer.removeStartingWindow(taskId, leash, frame, playRevealAnimation);
+        mSplashScreenExecutor.execute(() -> {
+            mStartingSurfaceDrawer.removeStartingWindow(taskId, leash, frame, playRevealAnimation);
+        });
     }
 
+    /**
+     * The interface for calls from outside the Shell, within the host process.
+     */
     private class StartingSurfaceImpl implements StartingSurface {
+        private IStartingWindowImpl mIStartingWindow;
 
         @Override
-        public void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
-            mSplashScreenExecutor.execute(() ->
-                    StartingWindowController.this.addStartingWindow(windowInfo, appToken));
+        public IStartingWindowImpl createExternalInterface() {
+            if (mIStartingWindow != null) {
+                mIStartingWindow.invalidate();
+            }
+            mIStartingWindow = new IStartingWindowImpl(StartingWindowController.this);
+            return mIStartingWindow;
+        }
+    }
+
+    /**
+     * The interface for calls from outside the host process.
+     */
+    @BinderThread
+    private static class IStartingWindowImpl extends IStartingWindow.Stub {
+        private StartingWindowController mController;
+        private IStartingWindowListener mListener;
+        private final BiConsumer<Integer, Integer> mStartingWindowListener =
+                this::notifyIStartingWindowListener;
+        private final IBinder.DeathRecipient mListenerDeathRecipient =
+                new IBinder.DeathRecipient() {
+                    @Override
+                    @BinderThread
+                    public void binderDied() {
+                        final StartingWindowController controller = mController;
+                        controller.getRemoteCallExecutor().execute(() -> {
+                            mListener = null;
+                            controller.setStartingWindowListener(null);
+                        });
+                    }
+                };
+
+        public IStartingWindowImpl(StartingWindowController controller) {
+            mController = controller;
+        }
+
+        /**
+         * Invalidates this instance, preventing future calls from updating the controller.
+         */
+        void invalidate() {
+            mController = null;
         }
 
         @Override
-        public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
-                boolean playRevealAnimation) {
-            mSplashScreenExecutor.execute(() ->
-                    StartingWindowController.this.removeStartingWindow(taskId, leash, frame,
-                            playRevealAnimation));
+        public void setStartingWindowListener(IStartingWindowListener listener) {
+            executeRemoteCallWithTaskPermission(mController, "setStartingWindowListener",
+                    (controller) -> {
+                        if (mListener != null) {
+                            // Reset the old death recipient
+                            mListener.asBinder().unlinkToDeath(mListenerDeathRecipient,
+                                    0 /* flags */);
+                        }
+                        if (listener != null) {
+                            try {
+                                listener.asBinder().linkToDeath(mListenerDeathRecipient,
+                                        0 /* flags */);
+                            } catch (RemoteException e) {
+                                Slog.e(TAG, "Failed to link to death");
+                                return;
+                            }
+                        }
+                        mListener = listener;
+                        controller.setStartingWindowListener(mStartingWindowListener);
+                    });
         }
 
-        @Override
-        public void copySplashScreenView(int taskId) {
-            mSplashScreenExecutor.execute(() ->
-                    StartingWindowController.this.copySplashScreenView(taskId));
-        }
+        private void notifyIStartingWindowListener(int taskId, int supportedType) {
+            if (mListener == null) {
+                return;
+            }
 
-        @Override
-        public void setStartingWindowListener(BiConsumer<Integer, Integer> listener) {
-            mSplashScreenExecutor.execute(() ->
-                    StartingWindowController.this.setStartingWindowListener(listener));
+            try {
+                mListener.onTaskLaunching(taskId, supportedType);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to notify task launching", e);
+            }
         }
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 629ff0d..b29b18b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -96,6 +96,17 @@
         };
         for (int i = info.getChanges().size() - 1; i >= 0; --i) {
             final TransitionInfo.Change change = info.getChanges().get(i);
+            if (change.getMode() == TRANSIT_CHANGE) {
+                // No default animation for this, so just update bounds/position.
+                t.setPosition(change.getLeash(),
+                        change.getEndAbsBounds().left - change.getEndRelOffset().x,
+                        change.getEndAbsBounds().top - change.getEndRelOffset().y);
+                if (change.getTaskInfo() != null) {
+                    // Skip non-tasks since those usually have null bounds.
+                    t.setWindowCrop(change.getLeash(),
+                            change.getEndAbsBounds().width(), change.getEndAbsBounds().height());
+                }
+            }
 
             // Don't animate anything that isn't independent.
             if (!TransitionInfo.isIndependent(change, info)) continue;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/IShellTransitions.aidl
similarity index 63%
copy from libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitions.java
copy to libs/WindowManager/Shell/src/com/android/wm/shell/transition/IShellTransitions.aidl
index 85bbf74..dffc700 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/IShellTransitions.aidl
@@ -16,25 +16,22 @@
 
 package com.android.wm.shell.transition;
 
-import android.annotation.NonNull;
 import android.window.IRemoteTransition;
 import android.window.TransitionFilter;
 
-import com.android.wm.shell.common.annotations.ExternalThread;
-
 /**
- * Interface to manage remote transitions.
+ * Interface that is exposed to remote callers to manipulate the transitions feature.
  */
-@ExternalThread
-public interface RemoteTransitions {
-    /**
-     * Registers a remote transition.
-     */
-    void registerRemote(@NonNull TransitionFilter filter,
-            @NonNull IRemoteTransition remoteTransition);
+interface IShellTransitions {
 
     /**
-     * Unregisters a remote transition.
+     * Registers a remote transition handler.
      */
-    void unregisterRemote(@NonNull IRemoteTransition remoteTransition);
+    oneway void registerRemote(in TransitionFilter filter,
+            in IRemoteTransition remoteTransition) = 1;
+
+    /**
+     * Unregisters a remote transition handler.
+     */
+    oneway void unregisterRemote(in IRemoteTransition remoteTransition) = 2;
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
index ac93a17..9667f4b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
@@ -16,6 +16,8 @@
 
 package com.android.wm.shell.transition;
 
+import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.IBinder;
@@ -23,6 +25,7 @@
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Pair;
+import android.util.Slog;
 import android.view.SurfaceControl;
 import android.window.IRemoteTransition;
 import android.window.IRemoteTransitionFinishedCallback;
@@ -31,6 +34,8 @@
 import android.window.TransitionRequestInfo;
 import android.window.WindowContainerTransaction;
 
+import androidx.annotation.BinderThread;
+
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
@@ -42,6 +47,8 @@
  * if the request includes a specific remote.
  */
 public class RemoteTransitionHandler implements Transitions.TransitionHandler {
+    private static final String TAG = "RemoteTransitionHandler";
+
     private final ShellExecutor mMainExecutor;
 
     /** Includes remotes explicitly requested by, eg, ActivityOptions */
@@ -51,15 +58,33 @@
     private final ArrayList<Pair<TransitionFilter, IRemoteTransition>> mFilters =
             new ArrayList<>();
 
+    private final IBinder.DeathRecipient mTransitionDeathRecipient =
+            new IBinder.DeathRecipient() {
+                @Override
+                @BinderThread
+                public void binderDied() {
+                    mMainExecutor.execute(() -> {
+                        mFilters.clear();
+                    });
+                }
+            };
+
     RemoteTransitionHandler(@NonNull ShellExecutor mainExecutor) {
         mMainExecutor = mainExecutor;
     }
 
     void addFiltered(TransitionFilter filter, IRemoteTransition remote) {
+        try {
+            remote.asBinder().linkToDeath(mTransitionDeathRecipient, 0 /* flags */);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Failed to link to death");
+            return;
+        }
         mFilters.add(new Pair<>(filter, remote));
     }
 
     void removeFiltered(IRemoteTransition remote) {
+        remote.asBinder().unlinkToDeath(mTransitionDeathRecipient, 0 /* flags */);
         for (int i = mFilters.size() - 1; i >= 0; --i) {
             if (mFilters.get(i).second == remote) {
                 mFilters.remove(i);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ShellTransitions.java
similarity index 83%
rename from libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitions.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/transition/ShellTransitions.java
index 85bbf74..bc42c6e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ShellTransitions.java
@@ -26,7 +26,15 @@
  * Interface to manage remote transitions.
  */
 @ExternalThread
-public interface RemoteTransitions {
+public interface ShellTransitions {
+
+    /**
+     * Returns a binder that can be passed to an external process to manipulate remote transitions.
+     */
+    default IShellTransitions createExternalInterface() {
+        return null;
+    }
+
     /**
      * Registers a remote transition.
      */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index 677db10..ca1b53d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -23,6 +23,8 @@
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
 import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
 
+import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ContentResolver;
@@ -51,6 +53,7 @@
 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.RemoteCallable;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.TransactionPool;
 import com.android.wm.shell.common.annotations.ExternalThread;
@@ -60,7 +63,7 @@
 import java.util.Arrays;
 
 /** Plays transition animations */
-public class Transitions {
+public class Transitions implements RemoteCallable<Transitions> {
     static final String TAG = "ShellTransitions";
 
     /** Set to {@code true} to enable shell transitions. */
@@ -73,7 +76,7 @@
     private final ShellExecutor mAnimExecutor;
     private final TransitionPlayerImpl mPlayerImpl;
     private final RemoteTransitionHandler mRemoteTransitionHandler;
-    private final RemoteTransitionImpl mImpl = new RemoteTransitionImpl();
+    private final ShellTransitionImpl mImpl = new ShellTransitionImpl();
 
     /** List of possible handlers. Ordered by specificity (eg. tapped back to front). */
     private final ArrayList<TransitionHandler> mHandlers = new ArrayList<>();
@@ -87,10 +90,6 @@
     /** Keeps track of currently tracked transitions and all the animations associated with each */
     private final ArrayMap<IBinder, ActiveTransition> mActiveTransitions = new ArrayMap<>();
 
-    public static RemoteTransitions asRemoteTransitions(Transitions transitions) {
-        return transitions.mImpl;
-    }
-
     public Transitions(@NonNull WindowOrganizer organizer, @NonNull TransactionPool pool,
             @NonNull Context context, @NonNull ShellExecutor mainExecutor,
             @NonNull ShellExecutor animExecutor) {
@@ -126,6 +125,20 @@
         mRemoteTransitionHandler = null;
     }
 
+    public ShellTransitions asRemoteTransitions() {
+        return mImpl;
+    }
+
+    @Override
+    public Context getContext() {
+        return mContext;
+    }
+
+    @Override
+    public ShellExecutor getRemoteCallExecutor() {
+        return mMainExecutor;
+    }
+
     private void dispatchAnimScaleSetting(float scale) {
         for (int i = mHandlers.size() - 1; i >= 0; --i) {
             mHandlers.get(i).setAnimScaleSetting(scale);
@@ -134,8 +147,8 @@
 
     /** Create an empty/non-registering transitions object for system-ui tests. */
     @VisibleForTesting
-    public static RemoteTransitions createEmptyForTesting() {
-        return new RemoteTransitions() {
+    public static ShellTransitions createEmptyForTesting() {
+        return new ShellTransitions() {
             @Override
             public void registerRemote(@androidx.annotation.NonNull TransitionFilter filter,
                     @androidx.annotation.NonNull IRemoteTransition remoteTransition) {
@@ -426,24 +439,74 @@
         }
     }
 
+    /**
+     * The interface for calls from outside the Shell, within the host process.
+     */
     @ExternalThread
-    private class RemoteTransitionImpl implements RemoteTransitions {
+    private class ShellTransitionImpl implements ShellTransitions {
+        private IShellTransitionsImpl mIShellTransitions;
+
+        @Override
+        public IShellTransitions createExternalInterface() {
+            if (mIShellTransitions != null) {
+                mIShellTransitions.invalidate();
+            }
+            mIShellTransitions = new IShellTransitionsImpl(Transitions.this);
+            return mIShellTransitions;
+        }
+
         @Override
         public void registerRemote(@NonNull TransitionFilter filter,
                 @NonNull IRemoteTransition remoteTransition) {
             mMainExecutor.execute(() -> {
-                Transitions.this.registerRemote(filter, remoteTransition);
+                mRemoteTransitionHandler.addFiltered(filter, remoteTransition);
             });
         }
 
         @Override
         public void unregisterRemote(@NonNull IRemoteTransition remoteTransition) {
             mMainExecutor.execute(() -> {
-                Transitions.this.unregisterRemote(remoteTransition);
+                mRemoteTransitionHandler.removeFiltered(remoteTransition);
             });
         }
     }
 
+    /**
+     * The interface for calls from outside the host process.
+     */
+    @BinderThread
+    private static class IShellTransitionsImpl extends IShellTransitions.Stub {
+        private Transitions mTransitions;
+
+        IShellTransitionsImpl(Transitions transitions) {
+            mTransitions = transitions;
+        }
+
+        /**
+         * Invalidates this instance, preventing future calls from updating the controller.
+         */
+        void invalidate() {
+            mTransitions = null;
+        }
+
+        @Override
+        public void registerRemote(@NonNull TransitionFilter filter,
+                @NonNull IRemoteTransition remoteTransition) {
+            executeRemoteCallWithTaskPermission(mTransitions, "registerRemote",
+                    (transitions) -> {
+                        transitions.mRemoteTransitionHandler.addFiltered(filter, remoteTransition);
+                    });
+        }
+
+        @Override
+        public void unregisterRemote(@NonNull IRemoteTransition remoteTransition) {
+            executeRemoteCallWithTaskPermission(mTransitions, "unregisterRemote",
+                    (transitions) -> {
+                        transitions.mRemoteTransitionHandler.removeFiltered(remoteTransition);
+                    });
+        }
+    }
+
     private class SettingsObserver extends ContentObserver {
 
         SettingsObserver() {
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/EnterSplitScreenNotSupportNonResizable.kt
similarity index 72%
rename from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNonResizableNotDock.kt
rename to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt
index 219da27..7d22d4d 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/EnterSplitScreenNotSupportNonResizable.kt
@@ -16,6 +16,8 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
+import android.platform.test.annotations.Postsubmit
+import android.provider.Settings
 import android.view.Surface
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
@@ -28,7 +30,9 @@
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import com.android.wm.shell.flicker.dockedStackDividerIsInvisible
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
+import org.junit.After
 import org.junit.Assert
+import org.junit.Before
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -36,27 +40,31 @@
 import org.junit.runners.Parameterized
 
 /**
- * Test open non-resizable activity will auto exit split screen mode
- * To run this test: `atest WMShellFlickerTests:EnterSplitScreenNonResizableNotDock`
+ * Test enter split screen from non-resizable activity. When the device doesn't support
+ * non-resizable in multi window, there should be no button to enter split screen for non-resizable
+ * activity.
+ *
+ * To run this test: `atest WMShellFlickerTests:EnterSplitScreenNotSupportNonResizable`
  */
+@Postsubmit
 @RequiresDevice
 @RunWith(Parameterized::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FlakyTest(bugId = 173875043)
-class EnterSplitScreenNonResizableNotDock(
+class EnterSplitScreenNotSupportNonResizable(
     testSpec: FlickerTestParameter
 ) : LegacySplitScreenTransition(testSpec) {
+    var prevSupportNonResizableInMultiWindow = 0
+
     override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
-            super.transition(this, configuration)
-            teardown {
+            cleanSetup(this, configuration)
+            setup {
                 eachRun {
-                    nonResizeableApp.exit(wmHelper)
+                    nonResizeableApp.launchViaIntent(wmHelper)
                 }
             }
             transitions {
-                nonResizeableApp.launchViaIntent(wmHelper)
                 device.openQuickstep(wmHelper)
                 if (device.canSplitScreen(wmHelper)) {
                     Assert.fail("Non-resizeable app should not enter split screen")
@@ -71,8 +79,23 @@
             nonResizeableApp.defaultWindowName,
             splitScreenApp.defaultWindowName)
 
-    @Test
-    fun dockedStackDividerIsInvisible() = testSpec.dockedStackDividerIsInvisible()
+    @Before
+    fun setup() {
+        prevSupportNonResizableInMultiWindow = Settings.Global.getInt(context.contentResolver,
+                Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW)
+        if (prevSupportNonResizableInMultiWindow == 1) {
+            // Not support non-resizable in multi window
+            Settings.Global.putInt(context.contentResolver,
+                    Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, 0)
+        }
+    }
+
+    @After
+    fun teardown() {
+        Settings.Global.putInt(context.contentResolver,
+                Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW,
+                prevSupportNonResizableInMultiWindow)
+    }
 
     @FlakyTest(bugId = 178447631)
     @Test
@@ -84,6 +107,9 @@
         super.visibleWindowsShownMoreThanOneConsecutiveEntry()
 
     @Test
+    fun dockedStackDividerIsInvisible() = testSpec.dockedStackDividerIsInvisible()
+
+    @Test
     fun appWindowIsVisible() {
         testSpec.assertWmEnd {
             isInvisible(nonResizeableApp.defaultWindowName)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt
new file mode 100644
index 0000000..9b4a103
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt
@@ -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.wm.shell.flicker.legacysplitscreen
+
+import android.platform.test.annotations.Postsubmit
+import android.provider.Settings
+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.helpers.launchSplitScreen
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import com.android.wm.shell.flicker.dockedStackDividerIsVisible
+import com.android.wm.shell.flicker.helpers.SplitScreenHelper
+import org.junit.After
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test enter split screen from non-resizable activity. When the device supports
+ * non-resizable in multi window, there should be a button to enter split screen for non-resizable
+ * activity.
+ *
+ * To run this test: `atest WMShellFlickerTests:EnterSplitScreenSupportNonResizable`
+ */
+@Postsubmit
+@RequiresDevice
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+class EnterSplitScreenSupportNonResizable(
+    testSpec: FlickerTestParameter
+) : LegacySplitScreenTransition(testSpec) {
+    var prevSupportNonResizableInMultiWindow = 0
+
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+        get() = { configuration ->
+            cleanSetup(this, configuration)
+            setup {
+                eachRun {
+                    nonResizeableApp.launchViaIntent(wmHelper)
+                }
+            }
+            transitions {
+                device.launchSplitScreen(wmHelper)
+            }
+        }
+
+    override val ignoredWindows: List<String>
+        get() = listOf(LAUNCHER_PACKAGE_NAME,
+                WindowManagerStateHelper.SPLASH_SCREEN_NAME,
+                WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME,
+                nonResizeableApp.defaultWindowName,
+                splitScreenApp.defaultWindowName)
+
+    @Before
+    fun setup() {
+        prevSupportNonResizableInMultiWindow = Settings.Global.getInt(context.contentResolver,
+                Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW)
+        if (prevSupportNonResizableInMultiWindow != 1) {
+            // Support non-resizable in multi window
+            Settings.Global.putInt(context.contentResolver,
+                    Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, 1)
+        }
+    }
+
+    @After
+    fun teardown() {
+        Settings.Global.putInt(context.contentResolver,
+                Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW,
+                prevSupportNonResizableInMultiWindow)
+    }
+
+    @FlakyTest(bugId = 178447631)
+    @Test
+    override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+            super.visibleLayersShownMoreThanOneConsecutiveEntry()
+
+    @Test
+    override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+            super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+    @Test
+    fun dockedStackDividerIsVisible() = testSpec.dockedStackDividerIsVisible()
+
+    @Test
+    fun appWindowIsVisible() {
+        testSpec.assertWmEnd {
+            isVisible(nonResizeableApp.defaultWindowName)
+        }
+    }
+
+    companion object {
+        @Parameterized.Parameters(name = "{0}")
+        @JvmStatic
+        fun getParams(): Collection<FlickerTestParameter> {
+            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
+                    repetitions = SplitScreenHelper.TEST_REPETITIONS,
+                    supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
+        }
+    }
+}
\ No newline at end of file
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/LegacySplitScreenFromIntentNotSupportNonResizable.kt
similarity index 60%
copy from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreen.kt
copy to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt
index 4c6705f..8923845 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/LegacySplitScreenFromIntentNotSupportNonResizable.kt
@@ -16,7 +16,8 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
-import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.Postsubmit
+import android.provider.Settings
 import android.view.Surface
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
@@ -31,7 +32,10 @@
 import com.android.server.wm.flicker.layerBecomesVisible
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER
+import com.android.wm.shell.flicker.dockedStackDividerIsInvisible
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
+import org.junit.After
+import org.junit.Before
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -39,18 +43,20 @@
 import org.junit.runners.Parameterized
 
 /**
- * Test launch non resizable activity in split screen mode will trigger exit split screen mode
- * (Non resizable activity launch via intent)
- * To run this test: `atest WMShellFlickerTests:NonResizableLaunchInLegacySplitScreen`
+ * Test launch non-resizable activity via intent in split screen mode. When the device does not
+ * support non-resizable in multi window, it should trigger exit split screen.
+ * To run this test: `atest WMShellFlickerTests:LegacySplitScreenFromIntentNotSupportNonResizable`
  */
-@Presubmit
+@Postsubmit
 @RequiresDevice
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class NonResizableLaunchInLegacySplitScreen(
+class LegacySplitScreenFromIntentNotSupportNonResizable(
     testSpec: FlickerTestParameter
 ) : LegacySplitScreenTransition(testSpec) {
+    var prevSupportNonResizableInMultiWindow = 0
+
     override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
             cleanSetup(this, configuration)
@@ -72,33 +78,60 @@
             WindowManagerStateHelper.SPLASH_SCREEN_NAME,
             WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME)
 
-    @Presubmit
-    @Test
-    fun layerBecomesVisible() = testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName)
+    @Before
+    fun setup() {
+        prevSupportNonResizableInMultiWindow = Settings.Global.getInt(context.contentResolver,
+                Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW)
+        if (prevSupportNonResizableInMultiWindow == 1) {
+            // Not support non-resizable in multi window
+            Settings.Global.putInt(context.contentResolver,
+                    Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, 0)
+        }
+    }
 
-    @Presubmit
-    @Test
-    fun layerBecomesInvisible() = testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName)
+    @After
+    fun teardown() {
+        Settings.Global.putInt(context.contentResolver,
+                Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW,
+                prevSupportNonResizableInMultiWindow)
+    }
 
     @FlakyTest(bugId = 178447631)
     @Test
     override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
-        super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
-    @Presubmit
-    @Test
-    fun appWindowBecomesVisible() =
-        testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName)
-
-    @Presubmit
-    @Test
-    fun appWindowBecomesInVisible() =
-        testSpec.appWindowBecomesInVisible(splitScreenApp.defaultWindowName)
+            super.visibleLayersShownMoreThanOneConsecutiveEntry()
 
     @FlakyTest(bugId = 178447631)
     @Test
     override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
-        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+            super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+    @Test
+    fun resizableAppLayerBecomesInvisible() =
+            testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName)
+
+    @Test
+    fun nonResizableAppLayerBecomesVisible() =
+            testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName)
+
+    @Test
+    fun resizableAppWindowBecomesInvisible() =
+            testSpec.appWindowBecomesInVisible(splitScreenApp.defaultWindowName)
+
+    @Test
+    fun nonResizableAppWindowBecomesVisible() =
+            testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName)
+
+    @Test
+    fun dockedStackDividerIsInvisibleAtEnd() = testSpec.dockedStackDividerIsInvisible()
+
+    @Test
+    fun onlyNonResizableAppWindowIsVisibleAtEnd() {
+        testSpec.assertWmEnd {
+            isInvisible(splitScreenApp.defaultWindowName)
+            isVisible(nonResizeableApp.defaultWindowName)
+        }
+    }
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
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/LegacySplitScreenFromIntentSupportNonResizable.kt
similarity index 63%
rename from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreen.kt
rename to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt
index 4c6705f..2f5e0bd 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/LegacySplitScreenFromIntentSupportNonResizable.kt
@@ -16,22 +16,24 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
-import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.Postsubmit
+import android.provider.Settings
 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.appWindowBecomesInVisible
 import com.android.server.wm.flicker.appWindowBecomesVisible
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.layerBecomesInvisible
 import com.android.server.wm.flicker.layerBecomesVisible
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER
+import com.android.wm.shell.flicker.dockedStackDividerIsVisible
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
+import org.junit.After
+import org.junit.Before
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -39,18 +41,20 @@
 import org.junit.runners.Parameterized
 
 /**
- * Test launch non resizable activity in split screen mode will trigger exit split screen mode
- * (Non resizable activity launch via intent)
- * To run this test: `atest WMShellFlickerTests:NonResizableLaunchInLegacySplitScreen`
+ * Test launch non-resizable activity via intent in split screen mode. When the device supports
+ * non-resizable in multi window, it should show the non-resizable app in split screen.
+ * To run this test: `atest WMShellFlickerTests:LegacySplitScreenFromIntentSupportNonResizable`
  */
-@Presubmit
+@Postsubmit
 @RequiresDevice
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class NonResizableLaunchInLegacySplitScreen(
+class LegacySplitScreenFromIntentSupportNonResizable(
     testSpec: FlickerTestParameter
 ) : LegacySplitScreenTransition(testSpec) {
+    var prevSupportNonResizableInMultiWindow = 0
+
     override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
             cleanSetup(this, configuration)
@@ -72,33 +76,52 @@
             WindowManagerStateHelper.SPLASH_SCREEN_NAME,
             WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME)
 
-    @Presubmit
-    @Test
-    fun layerBecomesVisible() = testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName)
+    @Before
+    fun setup() {
+        prevSupportNonResizableInMultiWindow = Settings.Global.getInt(context.contentResolver,
+                Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW)
+        if (prevSupportNonResizableInMultiWindow == 0) {
+            // Support non-resizable in multi window
+            Settings.Global.putInt(context.contentResolver,
+                    Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, 1)
+        }
+    }
 
-    @Presubmit
-    @Test
-    fun layerBecomesInvisible() = testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName)
+    @After
+    fun teardown() {
+        Settings.Global.putInt(context.contentResolver,
+                Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW,
+                prevSupportNonResizableInMultiWindow)
+    }
 
     @FlakyTest(bugId = 178447631)
     @Test
     override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
-        super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
-    @Presubmit
-    @Test
-    fun appWindowBecomesVisible() =
-        testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName)
-
-    @Presubmit
-    @Test
-    fun appWindowBecomesInVisible() =
-        testSpec.appWindowBecomesInVisible(splitScreenApp.defaultWindowName)
+            super.visibleLayersShownMoreThanOneConsecutiveEntry()
 
     @FlakyTest(bugId = 178447631)
     @Test
     override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
-        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+            super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+    @Test
+    fun nonResizableAppLayerBecomesVisible() =
+            testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName)
+
+    @Test
+    fun nonResizableAppWindowBecomesVisible() =
+            testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName)
+
+    @Test
+    fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisible()
+
+    @Test
+    fun bothAppsWindowsAreVisibleAtEnd() {
+        testSpec.assertWmEnd {
+            isVisible(splitScreenApp.defaultWindowName)
+            isVisible(nonResizeableApp.defaultWindowName)
+        }
+    }
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
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/LegacySplitScreenFromRecentNotSupportNonResizable.kt
similarity index 61%
copy from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreen.kt
copy to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt
index 8a1715e..a42774d 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/LegacySplitScreenFromRecentNotSupportNonResizable.kt
@@ -16,7 +16,8 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
-import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.Postsubmit
+import android.provider.Settings
 import android.view.Surface
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
@@ -32,7 +33,10 @@
 import com.android.server.wm.flicker.layerBecomesVisible
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER
+import com.android.wm.shell.flicker.dockedStackDividerIsInvisible
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
+import org.junit.After
+import org.junit.Before
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -40,17 +44,20 @@
 import org.junit.runners.Parameterized
 
 /**
- * Test launch non resizable activity in split screen mode will trigger exit split screen mode
- * (Non resizable activity launch via recent overview)
- * To run this test: `atest WMShellFlickerTests:NonResizableDismissInLegacySplitScreen`
+ * Test launch non-resizable activity via recent overview in split screen mode. When the device does
+ * not support non-resizable in multi window, it should trigger exit split screen.
+ * To run this test: `atest WMShellFlickerTests:LegacySplitScreenFromRecentNotSupportNonResizable`
  */
+@Postsubmit
 @RequiresDevice
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class NonResizableDismissInLegacySplitScreen(
+class LegacySplitScreenFromRecentNotSupportNonResizable(
     testSpec: FlickerTestParameter
 ) : LegacySplitScreenTransition(testSpec) {
+    var prevSupportNonResizableInMultiWindow = 0
+
     override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
             cleanSetup(this, configuration)
@@ -68,37 +75,64 @@
 
     override val ignoredWindows: List<String>
         get() = listOf(DOCKED_STACK_DIVIDER, LAUNCHER_PACKAGE_NAME, LETTERBOX_NAME, TOAST_NAME,
-            splitScreenApp.defaultWindowName, nonResizeableApp.defaultWindowName,
-            WindowManagerStateHelper.SPLASH_SCREEN_NAME,
-            WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME)
+                splitScreenApp.defaultWindowName, nonResizeableApp.defaultWindowName,
+                WindowManagerStateHelper.SPLASH_SCREEN_NAME,
+                WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME)
 
-    @Presubmit
-    @Test
-    fun layerBecomesInvisible() = testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName)
+    @Before
+    fun setup() {
+        prevSupportNonResizableInMultiWindow = Settings.Global.getInt(context.contentResolver,
+                Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW)
+        if (prevSupportNonResizableInMultiWindow == 1) {
+            // Not support non-resizable in multi window
+            Settings.Global.putInt(context.contentResolver,
+                    Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, 0)
+        }
+    }
+
+    @After
+    fun teardown() {
+        Settings.Global.putInt(context.contentResolver,
+                Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW,
+                prevSupportNonResizableInMultiWindow)
+    }
 
     @FlakyTest(bugId = 178447631)
     @Test
     override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
         super.visibleLayersShownMoreThanOneConsecutiveEntry()
 
-    @Presubmit
-    @Test
-    fun layerBecomesVisible() = testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName)
-
-    @Presubmit
-    @Test
-    fun appWindowBecomesVisible() =
-        testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName)
-
-    @Presubmit
-    @Test
-    fun appWindowBecomesInVisible() =
-        testSpec.appWindowBecomesInVisible(splitScreenApp.defaultWindowName)
-
     @FlakyTest(bugId = 178447631)
     @Test
     override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
-        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+            super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+    @Test
+    fun resizableAppLayerBecomesInvisible() =
+            testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName)
+
+    @Test
+    fun nonResizableAppLayerBecomesVisible() =
+            testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName)
+
+    @Test
+    fun resizableAppWindowBecomesInvisible() =
+        testSpec.appWindowBecomesInVisible(splitScreenApp.defaultWindowName)
+
+    @Test
+    fun nonResizableAppWindowBecomesVisible() =
+        testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName)
+
+    @Test
+    fun dockedStackDividerIsInvisibleAtEnd() = testSpec.dockedStackDividerIsInvisible()
+
+    @Test
+    fun onlyNonResizableAppWindowIsVisibleAtEnd() {
+        testSpec.assertWmEnd {
+            isInvisible(splitScreenApp.defaultWindowName)
+            isVisible(nonResizeableApp.defaultWindowName)
+        }
+    }
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
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/LegacySplitScreenFromRecentSupportNonResizable.kt
similarity index 62%
rename from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreen.kt
rename to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt
index 8a1715e..14f6dee 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/LegacySplitScreenFromRecentSupportNonResizable.kt
@@ -16,23 +16,25 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
-import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.Postsubmit
+import android.provider.Settings
 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.appWindowBecomesInVisible
 import com.android.server.wm.flicker.appWindowBecomesVisible
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.launchSplitScreen
 import com.android.server.wm.flicker.helpers.reopenAppFromOverview
-import com.android.server.wm.flicker.layerBecomesInvisible
 import com.android.server.wm.flicker.layerBecomesVisible
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER
+import com.android.wm.shell.flicker.dockedStackDividerIsVisible
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
+import org.junit.After
+import org.junit.Before
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -40,17 +42,20 @@
 import org.junit.runners.Parameterized
 
 /**
- * Test launch non resizable activity in split screen mode will trigger exit split screen mode
- * (Non resizable activity launch via recent overview)
- * To run this test: `atest WMShellFlickerTests:NonResizableDismissInLegacySplitScreen`
+ * Test launch non-resizable activity via recent overview in split screen mode. When the device
+ * supports non-resizable in multi window, it should show the non-resizable app in split screen.
+ * To run this test: `atest WMShellFlickerTests:LegacySplitScreenFromRecentSupportNonResizable`
  */
+@Postsubmit
 @RequiresDevice
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class NonResizableDismissInLegacySplitScreen(
+class LegacySplitScreenFromRecentSupportNonResizable(
     testSpec: FlickerTestParameter
 ) : LegacySplitScreenTransition(testSpec) {
+    var prevSupportNonResizableInMultiWindow = 0
+
     override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
             cleanSetup(this, configuration)
@@ -68,37 +73,56 @@
 
     override val ignoredWindows: List<String>
         get() = listOf(DOCKED_STACK_DIVIDER, LAUNCHER_PACKAGE_NAME, LETTERBOX_NAME, TOAST_NAME,
-            splitScreenApp.defaultWindowName, nonResizeableApp.defaultWindowName,
-            WindowManagerStateHelper.SPLASH_SCREEN_NAME,
-            WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME)
+                splitScreenApp.defaultWindowName, nonResizeableApp.defaultWindowName,
+                WindowManagerStateHelper.SPLASH_SCREEN_NAME,
+                WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME)
 
-    @Presubmit
-    @Test
-    fun layerBecomesInvisible() = testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName)
+    @Before
+    fun setup() {
+        prevSupportNonResizableInMultiWindow = Settings.Global.getInt(context.contentResolver,
+                Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW)
+        if (prevSupportNonResizableInMultiWindow == 0) {
+            // Support non-resizable in multi window
+            Settings.Global.putInt(context.contentResolver,
+                    Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, 1)
+        }
+    }
+
+    @After
+    fun teardown() {
+        Settings.Global.putInt(context.contentResolver,
+                Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW,
+                prevSupportNonResizableInMultiWindow)
+    }
 
     @FlakyTest(bugId = 178447631)
     @Test
     override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
         super.visibleLayersShownMoreThanOneConsecutiveEntry()
 
-    @Presubmit
-    @Test
-    fun layerBecomesVisible() = testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName)
-
-    @Presubmit
-    @Test
-    fun appWindowBecomesVisible() =
-        testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName)
-
-    @Presubmit
-    @Test
-    fun appWindowBecomesInVisible() =
-        testSpec.appWindowBecomesInVisible(splitScreenApp.defaultWindowName)
-
     @FlakyTest(bugId = 178447631)
     @Test
     override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
-        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+            super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+    @Test
+    fun nonResizableAppLayerBecomesVisible() =
+            testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName)
+
+    @Test
+    fun nonResizableAppWindowBecomesVisible() =
+        testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName)
+
+    @Test
+    fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisible()
+
+    @Test
+    fun bothAppsWindowsAreVisibleAtEnd() {
+        testSpec.assertWmEnd {
+            isVisible(splitScreenApp.defaultWindowName)
+            isVisible(nonResizeableApp.defaultWindowName)
+        }
+    }
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
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 319fde1..e13056c 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,6 +17,7 @@
 package com.android.wm.shell.flicker.legacysplitscreen
 
 import android.app.Instrumentation
+import android.content.Context
 import android.platform.test.annotations.Presubmit
 import android.support.test.launcherhelper.LauncherStrategyFactory
 import android.view.Surface
@@ -36,6 +37,7 @@
 
 abstract class LegacySplitScreenTransition(protected val testSpec: FlickerTestParameter) {
     protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+    protected val context: Context = instrumentation.context
     protected val isRotated = testSpec.config.startRotation.isRotated()
     protected val splitScreenApp = SplitScreenHelper.getPrimary(instrumentation)
     protected val secondaryApp = SplitScreenHelper.getSecondary(instrumentation)
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 4847c98..cd20dde 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,10 +16,8 @@
 
 package com.android.wm.shell.flicker.pip
 
-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
@@ -64,7 +62,7 @@
         }
     }
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun pipWindowBecomesVisible() {
         testSpec.assertWm {
@@ -74,22 +72,6 @@
         }
     }
 
-    @FlakyTest(bugId = 140855415)
-    @Test
-    override fun navBarLayerIsAlwaysVisible() = super.navBarLayerIsAlwaysVisible()
-
-    @FlakyTest(bugId = 140855415)
-    @Test
-    override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
-
-    @FlakyTest(bugId = 140855415)
-    @Test
-    override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
-
-    @FlakyTest(bugId = 140855415)
-    @Test
-    override fun noUncoveredRegions() = super.noUncoveredRegions()
-
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
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
index d011419..f554ca3 100644
--- 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
@@ -16,7 +16,7 @@
 
 package com.android.wm.shell.flicker.pip
 
-import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.RequiresDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
@@ -55,19 +55,11 @@
             }
         }
 
-    @Postsubmit
-    @Test
-    override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
-
-    @Postsubmit
-    @Test
-    override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
-
-    @Postsubmit
+    @Presubmit
     @Test
     fun pipAlwaysVisible() = testSpec.assertWm { this.showsAppWindow(pipApp.windowName) }
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun pipLayerInsideDisplay() {
         testSpec.assertLayersStart {
@@ -75,7 +67,7 @@
         }
     }
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun pipWindowMovesUp() = testSpec.assertWmEnd {
         val initialState = this.trace?.first()?.wmState
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 49a1055..8ceef8a 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
@@ -18,7 +18,6 @@
 
 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
@@ -76,19 +75,19 @@
     override fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
         testSpec.config.endRotation, allStates = false)
 
-    @FlakyTest(bugId = 140855415)
+    @Presubmit
     @Test
     override fun navBarLayerRotatesAndScales() =
         testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation,
             testSpec.config.endRotation)
 
-    @FlakyTest(bugId = 140855415)
+    @Presubmit
     @Test
     override fun statusBarLayerRotatesScales() =
         testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation,
             testSpec.config.endRotation)
 
-    @FlakyTest(bugId = 140855415)
+    @Presubmit
     @Test
     fun appLayerRotates_StartingBounds() {
         testSpec.assertLayersStart {
@@ -97,7 +96,7 @@
         }
     }
 
-    @FlakyTest(bugId = 140855415)
+    @Presubmit
     @Test
     fun appLayerRotates_EndingBounds() {
         testSpec.assertLayersEnd {
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 67e1768..102af92 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.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
@@ -112,7 +111,7 @@
         }
     }
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun pipAlwaysVisible() = testSpec.assertWm {
         this.showsAppWindow(pipApp.windowName)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestShellExecutor.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestShellExecutor.java
index bf84a6e..da95c77 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestShellExecutor.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestShellExecutor.java
@@ -16,8 +16,6 @@
 
 package com.android.wm.shell;
 
-import android.os.Looper;
-
 import com.android.wm.shell.common.ShellExecutor;
 
 import java.util.ArrayList;
@@ -40,11 +38,6 @@
     }
 
     @Override
-    public void removeAllCallbacks() {
-        mRunnables.clear();
-    }
-
-    @Override
     public void removeCallbacks(Runnable r) {
         mRunnables.remove(r);
     }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
index 4cedc48..ef046d4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
@@ -29,6 +29,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
 
+import android.graphics.Insets;
 import android.graphics.Point;
 import android.view.InsetsSource;
 import android.view.InsetsSourceControl;
@@ -119,7 +120,8 @@
 
     private InsetsSourceControl[] insetsSourceControl() {
         return new InsetsSourceControl[]{
-                new InsetsSourceControl(ITYPE_IME, mock(SurfaceControl.class), new Point(0, 0))
+                new InsetsSourceControl(
+                        ITYPE_IME, mock(SurfaceControl.class), new Point(0, 0), Insets.NONE)
         };
     }
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
index c1c4c6d..2f2bbba 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
@@ -205,7 +205,7 @@
                 mPolicy.getTargets(mInsets), TYPE_FULLSCREEN);
 
         mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
-        verify(mSplitScreenStarter).startIntent(any(), any(), any(),
+        verify(mSplitScreenStarter).startIntent(any(), any(),
                 eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
     }
 
@@ -217,12 +217,12 @@
                 mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
 
         mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
-        verify(mSplitScreenStarter).startIntent(any(), any(), any(),
+        verify(mSplitScreenStarter).startIntent(any(), any(),
                 eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
         reset(mSplitScreenStarter);
 
         mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData);
-        verify(mSplitScreenStarter).startIntent(any(), any(), any(),
+        verify(mSplitScreenStarter).startIntent(any(), any(),
                 eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
     }
 
@@ -234,12 +234,12 @@
                 mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
 
         mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
-        verify(mSplitScreenStarter).startIntent(any(), any(), any(),
+        verify(mSplitScreenStarter).startIntent(any(), any(),
                 eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
         reset(mSplitScreenStarter);
 
         mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData);
-        verify(mSplitScreenStarter).startIntent(any(), any(), any(),
+        verify(mSplitScreenStarter).startIntent(any(), any(),
                 eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
     }
 
@@ -251,7 +251,7 @@
                 mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
 
         mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
-        verify(mSplitScreenStarter).startIntent(any(), any(), any(),
+        verify(mSplitScreenStarter).startIntent(any(), any(),
                 eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
     }
 
@@ -263,7 +263,7 @@
                 mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
 
         mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
-        verify(mSplitScreenStarter).startIntent(any(), any(), any(),
+        verify(mSplitScreenStarter).startIntent(any(), any(),
                 eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
     }
 
@@ -276,13 +276,13 @@
                 mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
 
         mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
-        verify(mSplitScreenStarter).startIntent(any(), any(), any(),
+        verify(mSplitScreenStarter).startIntent(any(), any(),
                 eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
         reset(mSplitScreenStarter);
 
         // TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs
         mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData);
-        verify(mSplitScreenStarter).startIntent(any(), any(), any(),
+        verify(mSplitScreenStarter).startIntent(any(), any(),
                 eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
     }
 
@@ -295,13 +295,13 @@
                 mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
 
         mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
-        verify(mSplitScreenStarter).startIntent(any(), any(), any(),
+        verify(mSplitScreenStarter).startIntent(any(), any(),
                 eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
         reset(mSplitScreenStarter);
 
         // TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs
         mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData);
-        verify(mSplitScreenStarter).startIntent(any(), any(), any(),
+        verify(mSplitScreenStarter).startIntent(any(), any(),
                 eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
     }
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
index b21276f..bd5fe2b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
@@ -16,11 +16,10 @@
 
 package com.android.wm.shell.onehanded;
 
-import static android.window.DisplayAreaOrganizer.FEATURE_ONE_HANDED;
-
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.never;
@@ -67,6 +66,8 @@
     @Mock
     OneHandedGestureHandler mMockGestureHandler;
     @Mock
+    OneHandedSettingsUtil mMockSettingsUitl;
+    @Mock
     OneHandedUiEventLogger mMockUiEventLogger;
     @Mock
     IOverlayManager mMockOverlayManager;
@@ -79,13 +80,9 @@
     @Mock
     Handler mMockShellMainHandler;
 
-    final boolean mDefaultEnabled = OneHandedSettingsUtil.getSettingsOneHandedModeEnabled(
-            getTestContext().getContentResolver());
-    final boolean mDefaultSwipeToNotificationEnabled =
-            OneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled(
-                    getTestContext().getContentResolver());
-    final boolean mDefaultTapAppToExitEnabled = OneHandedSettingsUtil.getSettingsTapsAppToExit(
-            getTestContext().getContentResolver());
+    final boolean mDefaultEnabled = true;
+    final boolean mDefaultSwipeToNotificationEnabled = false;
+    final boolean mDefaultTapAppToExitEnabled = true;
 
     @Before
     public void setUp() {
@@ -97,6 +94,14 @@
         when(mMockDisplayAreaOrganizer.isInOneHanded()).thenReturn(false);
         when(mMockDisplayAreaOrganizer.getDisplayAreaTokenMap()).thenReturn(new ArrayMap<>());
         when(mMockBackgroundOrganizer.getBackgroundSurface()).thenReturn(mMockLeash);
+        when(mMockSettingsUitl.getSettingsOneHandedModeEnabled(any())).thenReturn(
+                mDefaultEnabled);
+        when(mMockSettingsUitl.getSettingsOneHandedModeTimeout(any())).thenReturn(
+                OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS);
+        when(mMockSettingsUitl.getSettingsTapsAppToExit(any())).thenReturn(
+                mDefaultTapAppToExitEnabled);
+        when(mMockSettingsUitl.getSettingsSwipeToNotificationEnabled(any())).thenReturn(
+                mDefaultSwipeToNotificationEnabled);
 
         mSpiedOneHandedController = spy(new OneHandedController(
                 mContext,
@@ -107,6 +112,7 @@
                 mMockTouchHandler,
                 mMockTutorialHandler,
                 mMockGestureHandler,
+                mMockSettingsUitl,
                 mSpiedTimeoutHandler,
                 mMockUiEventLogger,
                 mMockOverlayManager,
@@ -128,15 +134,6 @@
     }
 
     @Test
-    public void testNoRegisterAndUnregisterInSameCall() {
-        if (mDefaultEnabled) {
-            verify(mMockDisplayAreaOrganizer, never()).unregisterOrganizer();
-        } else {
-            verify(mMockDisplayAreaOrganizer, never()).registerOrganizer(FEATURE_ONE_HANDED);
-        }
-    }
-
-    @Test
     public void testStartOneHandedShouldTriggerScheduleOffset() {
         when(mMockDisplayAreaOrganizer.isInOneHanded()).thenReturn(false);
         mSpiedOneHandedController.setOneHandedEnabled(true);
@@ -190,35 +187,39 @@
     public void testUpdateEnabled() {
         mSpiedOneHandedController.setOneHandedEnabled(true);
 
-        verify(mMockTouchHandler, atLeastOnce()).onOneHandedEnabled(mDefaultEnabled);
-        verify(mMockGestureHandler, atLeastOnce()).onOneHandedEnabled(
-                mDefaultEnabled || mDefaultSwipeToNotificationEnabled);
+        verify(mMockTouchHandler, atLeastOnce()).onOneHandedEnabled(anyBoolean());
+        verify(mMockGestureHandler, atLeastOnce()).onOneHandedEnabled(anyBoolean());
     }
 
     @Test
     public void testUpdateSwipeToNotification() {
         mSpiedOneHandedController.setSwipeToNotificationEnabled(mDefaultSwipeToNotificationEnabled);
 
-        verify(mMockTouchHandler, atLeastOnce()).onOneHandedEnabled(mDefaultEnabled);
-        verify(mMockGestureHandler, atLeastOnce()).onOneHandedEnabled(
-                mDefaultEnabled || mDefaultSwipeToNotificationEnabled);
+        verify(mMockTouchHandler, atLeastOnce()).onOneHandedEnabled(anyBoolean());
+        verify(mMockGestureHandler, atLeastOnce()).onOneHandedEnabled(anyBoolean());
     }
 
     @Test
-    public void testSettingsObserverUpdateTapAppToExit() {
-        mSpiedOneHandedController.onTaskChangeExitSettingChanged();
-        if (mDefaultTapAppToExitEnabled) {
-            verify(mMockTaskStackListener, atLeastOnce()).addListener(any());
-        } else {
-            verify(mMockTaskStackListener, atLeastOnce()).removeListener(any());
-        }
+    public void testTapAppToExitEnabledAddListener() {
+        mSpiedOneHandedController.setTaskChangeToExit(mDefaultTapAppToExitEnabled);
+
+        // If device settings default ON, then addListener() will be trigger 1 time at init
+        verify(mMockTaskStackListener, atLeastOnce()).addListener(any());
+    }
+
+    @Test
+    public void testTapAppToExitDisabledRemoveListener() {
+        mSpiedOneHandedController.setTaskChangeToExit(!mDefaultTapAppToExitEnabled);
+
+        // If device settings default ON, then removeListener() will be trigger 1 time at init
+        verify(mMockTaskStackListener, atLeastOnce()).removeListener(any());
     }
 
     @Test
     public void testSettingsObserverUpdateEnabled() {
         mSpiedOneHandedController.onEnabledSettingChanged();
 
-        verify(mSpiedOneHandedController).setOneHandedEnabled(mDefaultEnabled);
+        verify(mSpiedOneHandedController).setOneHandedEnabled(anyBoolean());
     }
 
     @Test
@@ -232,14 +233,7 @@
     public void testSettingsObserverUpdateSwipeToNotification() {
         mSpiedOneHandedController.onSwipeToNotificationEnabledSettingChanged();
 
-        // Swipe to notification function is opposite with one handed mode function
-        if (mDefaultSwipeToNotificationEnabled) {
-            verify(mSpiedOneHandedController).setSwipeToNotificationEnabled(
-                    mDefaultSwipeToNotificationEnabled);
-        } else {
-            verify(mSpiedOneHandedController, never()).setSwipeToNotificationEnabled(
-                    mDefaultSwipeToNotificationEnabled);
-        }
+        verify(mSpiedOneHandedController).setSwipeToNotificationEnabled(anyBoolean());
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedSettingsUtilTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedSettingsUtilTest.java
index 61643d8..1e6c41a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedSettingsUtilTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedSettingsUtilTest.java
@@ -16,17 +16,11 @@
 
 package com.android.wm.shell.onehanded;
 
-import static com.android.wm.shell.onehanded.OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_LONG_IN_SECONDS;
-import static com.android.wm.shell.onehanded.OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS;
-import static com.android.wm.shell.onehanded.OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_NEVER;
-import static com.android.wm.shell.onehanded.OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_SHORT_IN_SECONDS;
-
-import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
 
 import android.content.ContentResolver;
 import android.database.ContentObserver;
-import android.net.Uri;
-import android.provider.Settings;
 import android.testing.AndroidTestingRunner;
 
 import androidx.test.filters.SmallTest;
@@ -34,76 +28,30 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 public class OneHandedSettingsUtilTest extends OneHandedTestCase {
-    ContentResolver mContentResolver;
-    ContentObserver mContentObserver;
-    boolean mOnChanged;
+    OneHandedSettingsUtil mSettingsUtil;
+
+    @Mock
+    ContentResolver mMockContentResolver;
+    @Mock
+    ContentObserver mMockContentObserver;
 
     @Before
     public void setUp() {
-        mContentResolver = mContext.getContentResolver();
-        mContentObserver = new ContentObserver(mContext.getMainThreadHandler()) {
-            @Override
-            public void onChange(boolean selfChange) {
-                super.onChange(selfChange);
-                mOnChanged = true;
-            }
-        };
-    }
+        MockitoAnnotations.initMocks(this);
 
-    @Test
-    public void testRegisterSecureKeyObserver() {
-        final Uri result = OneHandedSettingsUtil.registerSettingsKeyObserver(
-                Settings.Secure.TAPS_APP_TO_EXIT, mContentResolver, mContentObserver);
-
-        assertThat(result).isNotNull();
-
-        OneHandedSettingsUtil.registerSettingsKeyObserver(
-                Settings.Secure.TAPS_APP_TO_EXIT, mContentResolver, mContentObserver);
+        mSettingsUtil = new OneHandedSettingsUtil();
     }
 
     @Test
     public void testUnregisterSecureKeyObserver() {
-        OneHandedSettingsUtil.registerSettingsKeyObserver(
-                Settings.Secure.TAPS_APP_TO_EXIT, mContentResolver, mContentObserver);
-        OneHandedSettingsUtil.unregisterSettingsKeyObserver(mContentResolver, mContentObserver);
+        mSettingsUtil.unregisterSettingsKeyObserver(mMockContentResolver, mMockContentObserver);
 
-        assertThat(mOnChanged).isFalse();
-
-        Settings.Secure.putInt(mContext.getContentResolver(),
-                Settings.Secure.TAPS_APP_TO_EXIT, 0);
-
-        assertThat(mOnChanged).isFalse();
-    }
-
-    @Test
-    public void testGetSettingsIsOneHandedModeEnabled() {
-        assertThat(OneHandedSettingsUtil.getSettingsOneHandedModeEnabled(
-                mContentResolver)).isAnyOf(true, false);
-    }
-
-    @Test
-    public void testGetSettingsTapsAppToExit() {
-        assertThat(OneHandedSettingsUtil.getSettingsTapsAppToExit(
-                mContentResolver)).isAnyOf(true, false);
-    }
-
-    @Test
-    public void testGetSettingsOneHandedModeTimeout() {
-        assertThat(OneHandedSettingsUtil.getSettingsOneHandedModeTimeout(
-                mContentResolver)).isAnyOf(
-                ONE_HANDED_TIMEOUT_NEVER,
-                ONE_HANDED_TIMEOUT_SHORT_IN_SECONDS,
-                ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS,
-                ONE_HANDED_TIMEOUT_LONG_IN_SECONDS);
-    }
-
-    @Test
-    public void testGetSettingsSwipeToNotificationEnabled() {
-        assertThat(OneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled(
-                mContentResolver)).isAnyOf(true, false);
+        verify(mMockContentResolver).unregisterContentObserver(any());
     }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
index 69c537c..f586dda 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
@@ -64,6 +64,8 @@
     Handler mMockShellMainHandler;
     @Mock
     OneHandedUiEventLogger mMockUiEventLogger;
+    @Mock
+    OneHandedSettingsUtil mMockSettingsUtil;
 
     @Before
     public void setUp() {
@@ -80,6 +82,7 @@
                 mMockTouchHandler,
                 mMockTutorialHandler,
                 mMockGestureHandler,
+                mMockSettingsUtil,
                 mTimeoutHandler,
                 mMockUiEventLogger,
                 mMockOverlayManager,
diff --git a/libs/hwui/effects/StretchEffect.cpp b/libs/hwui/effects/StretchEffect.cpp
index d4fd105..9e4fb8f 100644
--- a/libs/hwui/effects/StretchEffect.cpp
+++ b/libs/hwui/effects/StretchEffect.cpp
@@ -33,7 +33,8 @@
     uniform float uMaxStretchIntensity;
 
     // Maximum percentage to stretch beyond bounds  of target
-    uniform float uStretchAffectedDist;
+    uniform float uStretchAffectedDistX;
+    uniform float uStretchAffectedDistY;
 
     // Distance stretched as a function of the normalized overscroll times
     // scale intensity
@@ -138,7 +139,7 @@
             outU,
             inU,
             uOverscrollX,
-            uStretchAffectedDist,
+            uStretchAffectedDistX,
             uDistanceStretchedX,
             uDistDiffX
         );
@@ -146,7 +147,7 @@
             outV,
             inV,
             uOverscrollY,
-            uStretchAffectedDist,
+            uStretchAffectedDistY,
             uDistanceStretchedY,
             uDistDiffY
         );
@@ -166,16 +167,14 @@
         return mStretchFilter;
     }
 
-    float distanceNotStretchedX = maxStretchAmount / stretchArea.width();
-    float distanceNotStretchedY = maxStretchAmount / stretchArea.height();
-    float normOverScrollDistX = mStretchDirection.x();
-    float normOverScrollDistY = mStretchDirection.y();
-    float distanceStretchedX = maxStretchAmount / (1 + abs(normOverScrollDistX));
-    float distanceStretchedY = maxStretchAmount / (1 + abs(normOverScrollDistY));
-    float diffX = distanceStretchedX - distanceNotStretchedX;
-    float diffY = distanceStretchedY - distanceNotStretchedY;
     float viewportWidth = stretchArea.width();
     float viewportHeight = stretchArea.height();
+    float normOverScrollDistX = mStretchDirection.x();
+    float normOverScrollDistY = mStretchDirection.y();
+    float distanceStretchedX = maxStretchAmountX / (1 + abs(normOverScrollDistX));
+    float distanceStretchedY = maxStretchAmountY / (1 + abs(normOverScrollDistY));
+    float diffX = distanceStretchedX;
+    float diffY = distanceStretchedY;
 
     if (mBuilder == nullptr) {
         mBuilder = std::make_unique<SkRuntimeShaderBuilder>(getStretchEffect());
@@ -183,7 +182,8 @@
 
     mBuilder->child("uContentTexture") = snapshotImage->makeShader(
             SkTileMode::kClamp, SkTileMode::kClamp, SkSamplingOptions(SkFilterMode::kLinear));
-    mBuilder->uniform("uStretchAffectedDist").set(&maxStretchAmount, 1);
+    mBuilder->uniform("uStretchAffectedDistX").set(&maxStretchAmountX, 1);
+    mBuilder->uniform("uStretchAffectedDistY").set(&maxStretchAmountY, 1);
     mBuilder->uniform("uDistanceStretchedX").set(&distanceStretchedX, 1);
     mBuilder->uniform("uDistanceStretchedY").set(&distanceStretchedY, 1);
     mBuilder->uniform("uDistDiffX").set(&diffX, 1);
diff --git a/libs/hwui/effects/StretchEffect.h b/libs/hwui/effects/StretchEffect.h
index d2da06b..8221b41 100644
--- a/libs/hwui/effects/StretchEffect.h
+++ b/libs/hwui/effects/StretchEffect.h
@@ -33,8 +33,12 @@
         SmoothStep,
     };
 
-    StretchEffect(const SkRect& area, const SkVector& direction, float maxStretchAmount)
-            : stretchArea(area), maxStretchAmount(maxStretchAmount), mStretchDirection(direction) {}
+    StretchEffect(const SkRect& area, const SkVector& direction, float maxStretchAmountX,
+                  float maxStretchAmountY)
+            : stretchArea(area)
+            , maxStretchAmountX(maxStretchAmountX)
+            , maxStretchAmountY(maxStretchAmountY)
+            , mStretchDirection(direction) {}
 
     StretchEffect() {}
 
@@ -50,7 +54,8 @@
         this->stretchArea = other.stretchArea;
         this->mStretchDirection = other.mStretchDirection;
         this->mStretchFilter = nullptr;
-        this->maxStretchAmount = other.maxStretchAmount;
+        this->maxStretchAmountX = other.maxStretchAmountX;
+        this->maxStretchAmountY = other.maxStretchAmountY;
         return *this;
     }
 
@@ -67,13 +72,15 @@
             return setEmpty();
         }
         stretchArea.join(other.stretchArea);
-        maxStretchAmount = std::max(maxStretchAmount, other.maxStretchAmount);
+        maxStretchAmountX = std::max(maxStretchAmountX, other.maxStretchAmountX);
+        maxStretchAmountY = std::max(maxStretchAmountY, other.maxStretchAmountY);
     }
 
     sk_sp<SkImageFilter> getImageFilter(const sk_sp<SkImage>& snapshotImage) const;
 
     SkRect stretchArea {0, 0, 0, 0};
-    float maxStretchAmount = 0;
+    float maxStretchAmountX = 0;
+    float maxStretchAmountY = 0;
 
     void setStretchDirection(const SkVector& direction) {
         mStretchFilter = nullptr;
diff --git a/libs/hwui/jni/android_graphics_RenderNode.cpp b/libs/hwui/jni/android_graphics_RenderNode.cpp
index fc7d0d1..fffa806 100644
--- a/libs/hwui/jni/android_graphics_RenderNode.cpp
+++ b/libs/hwui/jni/android_graphics_RenderNode.cpp
@@ -181,9 +181,10 @@
 
 static jboolean android_view_RenderNode_stretch(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,
                                                 jfloat left, jfloat top, jfloat right,
-                                                jfloat bottom, jfloat vX, jfloat vY, jfloat max) {
-    StretchEffect effect =
-            StretchEffect(SkRect::MakeLTRB(left, top, right, bottom), {.fX = vX, .fY = vY}, max);
+                                                jfloat bottom, jfloat vX, jfloat vY, jfloat maxX,
+                                                jfloat maxY) {
+    StretchEffect effect = StretchEffect(SkRect::MakeLTRB(left, top, right, bottom),
+                                         {.fX = vX, .fY = vY}, maxX, maxY);
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().mutateLayerProperties().mutableStretchEffect().mergeWith(
             effect);
@@ -662,7 +663,7 @@
             env->CallVoidMethod(localref, gPositionListener_ApplyStretchMethod,
                                 info.canvasContext.getFrameNumber(), area.left, area.top,
                                 area.right, area.bottom, stretchDirection.fX, stretchDirection.fY,
-                                effect->maxStretchAmount);
+                                effect->maxStretchAmountX, effect->maxStretchAmountY);
 #endif
             env->DeleteLocalRef(localref);
         }
@@ -738,7 +739,7 @@
         {"nSetOutlineEmpty", "(J)Z", (void*)android_view_RenderNode_setOutlineEmpty},
         {"nSetOutlineNone", "(J)Z", (void*)android_view_RenderNode_setOutlineNone},
         {"nClearStretch", "(J)Z", (void*)android_view_RenderNode_clearStretch},
-        {"nStretch", "(JFFFFFFF)Z", (void*)android_view_RenderNode_stretch},
+        {"nStretch", "(JFFFFFFFF)Z", (void*)android_view_RenderNode_stretch},
         {"nHasShadow", "(J)Z", (void*)android_view_RenderNode_hasShadow},
         {"nSetSpotShadowColor", "(JI)Z", (void*)android_view_RenderNode_setSpotShadowColor},
         {"nGetSpotShadowColor", "(J)I", (void*)android_view_RenderNode_getSpotShadowColor},
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index e8e2631..f957a73 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1988,7 +1988,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
-    public boolean setPreferredDeviceForCapturePreset(int capturePreset,
+    public boolean setPreferredDeviceForCapturePreset(@MediaRecorder.SystemSource int capturePreset,
                                                       @NonNull AudioDeviceAttributes device) {
         return setPreferredDevicesForCapturePreset(capturePreset, Arrays.asList(device));
     }
@@ -2002,7 +2002,8 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
-    public boolean clearPreferredDevicesForCapturePreset(int capturePreset) {
+    public boolean clearPreferredDevicesForCapturePreset(
+            @MediaRecorder.SystemSource int capturePreset) {
         if (!MediaRecorder.isValidAudioSource(capturePreset)) {
             return false;
         }
@@ -2024,7 +2025,8 @@
     @NonNull
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
-    public List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset(int capturePreset) {
+    public List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset(
+            @MediaRecorder.SystemSource int capturePreset) {
         if (!MediaRecorder.isValidAudioSource(capturePreset)) {
             return new ArrayList<AudioDeviceAttributes>();
         }
@@ -2036,7 +2038,8 @@
     }
 
     private boolean setPreferredDevicesForCapturePreset(
-            int capturePreset, @NonNull List<AudioDeviceAttributes> devices) {
+            @MediaRecorder.SystemSource int capturePreset,
+            @NonNull List<AudioDeviceAttributes> devices) {
         Objects.requireNonNull(devices);
         if (!MediaRecorder.isValidAudioSource(capturePreset)) {
             return false;
@@ -2081,7 +2084,8 @@
          * @param devices a list of newly set preferred audio devices
          */
         void onPreferredDevicesForCapturePresetChanged(
-                int capturePreset, @NonNull List<AudioDeviceAttributes> devices);
+                @MediaRecorder.SystemSource int capturePreset,
+                @NonNull List<AudioDeviceAttributes> devices);
     }
 
     /**
@@ -5287,7 +5291,10 @@
      *   otherwise (typically one device, except for duplicated paths).
      */
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MODIFY_AUDIO_ROUTING,
+            android.Manifest.permission.QUERY_AUDIO_STATE
+    })
     public @NonNull List<AudioDeviceAttributes> getDevicesForAttributes(
             @NonNull AudioAttributes attributes) {
         Objects.requireNonNull(attributes);
@@ -5426,7 +5433,10 @@
      * @return the volume behavior for the device
      */
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MODIFY_AUDIO_ROUTING,
+            android.Manifest.permission.QUERY_AUDIO_STATE
+    })
     public @DeviceVolumeBehavior
     int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
         // verify arguments (validity of device type is enforced in server)
@@ -5440,6 +5450,28 @@
         }
     }
 
+    /**
+     * @hide
+     * Returns {@code true} if the volume device behavior is {@link #DEVICE_VOLUME_BEHAVIOR_FULL}.
+     */
+    @TestApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MODIFY_AUDIO_ROUTING,
+            android.Manifest.permission.QUERY_AUDIO_STATE
+    })
+    public boolean isFullVolumeDevice() {
+        final AudioAttributes attributes = new AudioAttributes.Builder()
+                .setUsage(AudioAttributes.USAGE_MEDIA)
+                .build();
+        final List<AudioDeviceAttributes> devices = getDevicesForAttributes(attributes);
+        for (AudioDeviceAttributes device : devices) {
+            if (getDeviceVolumeBehavior(device) == DEVICE_VOLUME_BEHAVIOR_FULL) {
+                return true;
+            }
+        }
+        return false;
+    }
+
      /**
      * Indicate wired accessory connection state change.
      * @param device type of device connected/disconnected (AudioManager.DEVICE_OUT_xxx)
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index d7112d6..0d61399 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -612,7 +612,9 @@
         }
 
         /**
-         * Sets the context the record belongs to.
+         * Sets the context the record belongs to. This context will be used to pull information,
+         * such as attribution tags, which will be associated with the AudioRecord. However, the
+         * context itself will not be retained by the AudioRecord.
          * @param context a non-null {@link Context} instance
          * @return the same Builder instance.
          */
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 88731d2..bccefdf 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -2086,6 +2086,65 @@
     }
 
     /**
+     * Sets the streaming start threshold for an <code>AudioTrack</code>.
+     * <p> The streaming start threshold is the buffer level that the written audio
+     * data must reach for audio streaming to start after {@link #play()} is called.
+     * <p> For compressed streams, the size of a frame is considered to be exactly one byte.
+     *
+     * @param startThresholdInFrames the desired start threshold.
+     * @return the actual start threshold in frames value. This is
+     *         an integer between 1 to the buffer capacity
+     *         (see {@link #getBufferCapacityInFrames()}),
+     *         and might change if the output sink changes after track creation.
+     * @throws IllegalStateException if the track is not initialized or the
+     *         track transfer mode is not {@link #MODE_STREAM}.
+     * @throws IllegalArgumentException if startThresholdInFrames is not positive.
+     * @see #getStartThresholdInFrames()
+     */
+    public @IntRange(from = 1) int setStartThresholdInFrames(
+            @IntRange (from = 1) int startThresholdInFrames) {
+        if (mState != STATE_INITIALIZED) {
+            throw new IllegalStateException("AudioTrack is not initialized");
+        }
+        if (mDataLoadMode != MODE_STREAM) {
+            throw new IllegalStateException("AudioTrack must be a streaming track");
+        }
+        if (startThresholdInFrames < 1) {
+            throw new IllegalArgumentException("startThresholdInFrames "
+                    + startThresholdInFrames + " must be positive");
+        }
+        return native_setStartThresholdInFrames(startThresholdInFrames);
+    }
+
+    /**
+     * Returns the streaming start threshold of the <code>AudioTrack</code>.
+     * <p> The streaming start threshold is the buffer level that the written audio
+     * data must reach for audio streaming to start after {@link #play()} is called.
+     * When an <code>AudioTrack</code> is created, the streaming start threshold
+     * is the buffer capacity in frames. If the buffer size in frames is reduced
+     * by {@link #setBufferSizeInFrames(int)} to a value smaller than the start threshold
+     * then that value will be used instead for the streaming start threshold.
+     * <p> For compressed streams, the size of a frame is considered to be exactly one byte.
+     *
+     * @return the current start threshold in frames value. This is
+     *         an integer between 1 to the buffer capacity
+     *         (see {@link #getBufferCapacityInFrames()}),
+     *         and might change if the  output sink changes after track creation.
+     * @throws IllegalStateException if the track is not initialized or the
+     *         track is not {@link #MODE_STREAM}.
+     * @see #setStartThresholdInFrames(int)
+     */
+    public @IntRange (from = 1) int getStartThresholdInFrames() {
+        if (mState != STATE_INITIALIZED) {
+            throw new IllegalStateException("AudioTrack is not initialized");
+        }
+        if (mDataLoadMode != MODE_STREAM) {
+            throw new IllegalStateException("AudioTrack must be a streaming track");
+        }
+        return native_getStartThresholdInFrames();
+    }
+
+    /**
      *  Returns the frame count of the native <code>AudioTrack</code> buffer.
      *  @return current size in frames of the <code>AudioTrack</code> buffer.
      *  @throws IllegalStateException
@@ -4239,6 +4298,8 @@
     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(@Nullable String logSessionId);
+    private native int native_setStartThresholdInFrames(int startThresholdInFrames);
+    private native int native_getStartThresholdInFrames();
 
     /**
      * Sets the audio service Player Interface Id.
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 87e1e5b..dd08d8a 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -395,6 +395,26 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface Source {}
 
+    /** @hide */
+    @IntDef({
+        AudioSource.DEFAULT,
+        AudioSource.MIC,
+        AudioSource.VOICE_UPLINK,
+        AudioSource.VOICE_DOWNLINK,
+        AudioSource.VOICE_CALL,
+        AudioSource.CAMCORDER,
+        AudioSource.VOICE_RECOGNITION,
+        AudioSource.VOICE_COMMUNICATION,
+        AudioSource.REMOTE_SUBMIX,
+        AudioSource.UNPROCESSED,
+        AudioSource.VOICE_PERFORMANCE,
+        AudioSource.ECHO_REFERENCE,
+        AudioSource.RADIO_TUNER,
+        AudioSource.HOTWORD,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SystemSource {}
+
     // TODO make AudioSource static (API change) and move this method inside the AudioSource class
     /**
      * @hide
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index f09dcde..d49790e 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -19,6 +19,7 @@
     name: "libmedia_jni",
 
     defaults: ["libcodec2-internal-defaults"],
+    min_sdk_version: "",
 
     srcs: [
         "android_media_ImageWriter.cpp",
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
index 5afe0b5d..10d68ba 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
@@ -86,7 +86,7 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        mCm = ConnectivityManager.from(this);
+        mCm = getSystemService(ConnectivityManager.class);
         mUrl = getUrlForCaptivePortal();
         if (mUrl == null) {
             done(false);
@@ -161,7 +161,6 @@
         if (network != null) {
             network = network.getPrivateDnsBypassingCopy();
             mCm.bindProcessToNetwork(network);
-            mCm.setProcessDefaultNetworkForHostResolution(network);
         }
         mNetwork = network;
     }
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/ProvisionObserver.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/ProvisionObserver.java
index 78a02d7..43ca739 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/ProvisionObserver.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/ProvisionObserver.java
@@ -49,7 +49,7 @@
             case PROVISION_OBSERVER_REEVALUATION_JOB_ID:
                 if (isProvisioned(this)) {
                     Log.d(TAG, "device provisioned, force network re-evaluation");
-                    final ConnectivityManager connMgr = ConnectivityManager.from(this);
+                    final ConnectivityManager connMgr = getSystemService(ConnectivityManager.class);
                     Network[] info = connMgr.getAllNetworks();
                     for (Network nw : info) {
                         final NetworkCapabilities nc = connMgr.getNetworkCapabilities(nw);
diff --git a/packages/CompanionDeviceManager/res/values-af/strings.xml b/packages/CompanionDeviceManager/res/values-af/strings.xml
index ed120b5..36e59ba 100644
--- a/packages/CompanionDeviceManager/res/values-af/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-af/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Kies \'n <xliff:g id="PROFILE_NAME">%1$s</xliff:g> om deur &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; bestuur te word"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"toestel"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"horlosie"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Stel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; om jou &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; te bestuur"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Hierdie program is nodig om jou <xliff:g id="PROFILE_NAME">%1$s</xliff:g> te bestuur. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Laat toe"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Moenie toelaat nie"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-am/strings.xml b/packages/CompanionDeviceManager/res/values-am/strings.xml
index 76f68e7..0fefa8a 100644
--- a/packages/CompanionDeviceManager/res/values-am/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-am/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"በ&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; የሚተዳደር <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ይምረጡ"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"መሣሪያ"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ሰዓት"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; የእርስዎን <xliff:g id="DEVICE_NAME">%2$s</xliff:g> - &lt;strong&gt;&lt;/strong&gt; ለማስተዳደር"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"የእርስዎን <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ለማስተዳደር ይህ መተግበሪያ ያስፈልጋል <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"ፍቀድ"</string>
+    <string name="consent_no" msgid="2640796915611404382">"አትፍቀድ"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ar/strings.xml b/packages/CompanionDeviceManager/res/values-ar/strings.xml
index 92783a5..ca3b9f3 100644
--- a/packages/CompanionDeviceManager/res/values-ar/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ar/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"‏اختَر <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ليديره تطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"جهاز"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ساعة"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"‏ضبط &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; لإدارة &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"هذا التطبيق مطلوب لإدارة <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"السماح"</string>
+    <string name="consent_no" msgid="2640796915611404382">"عدم السماح"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-az/strings.xml b/packages/CompanionDeviceManager/res/values-az/strings.xml
index b07cad6..8e4a202 100644
--- a/packages/CompanionDeviceManager/res/values-az/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-az/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; tərəfindən idarə ediləcək <xliff:g id="PROFILE_NAME">%1$s</xliff:g> seçin"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"izləyin"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazınızı idarə etmək üçün &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ayarlayın"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Bu tətbiq <xliff:g id="PROFILE_NAME">%1$s</xliff:g> profilinizi idarə etmək üçün lazımdır. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"İcazə verin"</string>
+    <string name="consent_no" msgid="2640796915611404382">"İcazə verməyin"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
index edeaa77..ef19c48 100644
--- a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Odaberite profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"sat"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Podesite aplikaciju &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tako da upravlja uređajem &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Ova aplikacija je potrebna za upravljanje profilom <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Dozvoli"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Ne dozvoli"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-be/strings.xml b/packages/CompanionDeviceManager/res/values-be/strings.xml
index 9410d68..4366a08 100644
--- a/packages/CompanionDeviceManager/res/values-be/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-be/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Выберыце прыладу (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), якой будзе кіраваць праграма &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"прылада"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"гадзіннік"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Дазвольце праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; кіраваць прыладай &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Гэта праграма неабходная для кіравання профілем \"<xliff:g id="PROFILE_NAME">%1$s</xliff:g>\". <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Дазволіць"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Не дазваляць"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-bg/strings.xml b/packages/CompanionDeviceManager/res/values-bg/strings.xml
index 4457dbd..77f3413 100644
--- a/packages/CompanionDeviceManager/res/values-bg/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bg/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Изберете устройство (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), което да се управлява от &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"часовник"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Задайте &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да управлява устройството ви &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Това приложение е необходимо за управление на <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Разрешаване"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Забраняване"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-bn/strings.xml b/packages/CompanionDeviceManager/res/values-bn/strings.xml
index 4aa7e74..5fa4781 100644
--- a/packages/CompanionDeviceManager/res/values-bn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bn/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> বেছে নিন যেটি &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ম্যানেজ করবে"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ডিভাইস"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"দেখুন"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"আপনার &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ম্যানেজ করার জন্য &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; সেট করুন"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"আপনার <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ম্যানেজ করতে এই অ্যাপটি প্রয়োজন। <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"অনুমতি দিন"</string>
+    <string name="consent_no" msgid="2640796915611404382">"অনুমতি দেবেন না"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-bs/strings.xml b/packages/CompanionDeviceManager/res/values-bs/strings.xml
index 8ffa327..18153b5 100644
--- a/packages/CompanionDeviceManager/res/values-bs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bs/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Odaberite uređaj <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"sat"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Postavite aplikaciju &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da upravlja vašim uređajem &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Ova aplikacija je potrebna za upravljanje profilom: <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Dozvoli"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Nemoj dozvoliti"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ca/strings.xml b/packages/CompanionDeviceManager/res/values-ca/strings.xml
index c9c186e..bbd1125 100644
--- a/packages/CompanionDeviceManager/res/values-ca/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ca/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Tria un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> perquè el gestioni &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositiu"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"rellotge"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Defineix que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gestioni el dispositiu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Aquesta aplicació es necessita per gestionar <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Permet"</string>
+    <string name="consent_no" msgid="2640796915611404382">"No permetis"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-cs/strings.xml b/packages/CompanionDeviceManager/res/values-cs/strings.xml
index b2ac32d..c5fed33 100644
--- a/packages/CompanionDeviceManager/res/values-cs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-cs/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Vyberte zařízení <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, které chcete spravovat pomocí aplikace &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"zařízení"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"hodinky"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Nastavit aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pro správu vašeho zařízení: &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Tato aplikace je nutná pro správu profilu <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Povolit"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Nepovolovat"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-da/strings.xml b/packages/CompanionDeviceManager/res/values-da/strings.xml
index bc67948..21280d5 100644
--- a/packages/CompanionDeviceManager/res/values-da/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-da/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Vælg den enhed (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), som skal administreres af &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"enhed"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ur"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Indstil &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; til at administrere &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Du skal bruge denne app for at administrere dit <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Tillad"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Tillad ikke"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-el/strings.xml b/packages/CompanionDeviceManager/res/values-el/strings.xml
index fed516f..162d6fc 100644
--- a/packages/CompanionDeviceManager/res/values-el/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-el/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Επιλέξτε ένα προφίλ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> για διαχείριση από την εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"συσκευή"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ρολόι"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Ορίστε την εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; για διαχείριση της συσκευής &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Αυτή η εφαρμογή είναι απαραίτητη για τη διαχείριση του προφίλ σας <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Να επιτρέπεται"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Να μην επιτρέπεται"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
index 4fd057f..de89b39 100644
--- a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Set &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to manage your &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"This app is needed to manage your <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Allow"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
index 4fd057f..de89b39 100644
--- a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Set &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to manage your &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"This app is needed to manage your <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Allow"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
index 4fd057f..de89b39 100644
--- a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Set &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to manage your &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"This app is needed to manage your <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Allow"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
index 4fd057f..de89b39 100644
--- a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Set &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to manage your &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"This app is needed to manage your <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Allow"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml b/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
index 0e3902c..10c2012 100644
--- a/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
@@ -22,10 +22,7 @@
     <string name="profile_name_watch" msgid="576290739483672360">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‏‎‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‎‏‎‏‎‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎watch‎‏‎‎‏‎"</string>
     <!-- no translation found for confirmation_title (814973816731238955) -->
     <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="profile_summary" msgid="2059360676631420073">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‎‏‎‏‎‎‎‏‎‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‎‎‏‏‎‎‎‎‏‏‏‎‎‏‎‏‎‏‎‎‏‎This app is needed to manage your ‎‏‎‎‏‏‎<xliff:g id="PROFILE_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎. ‎‏‎‎‏‏‎<xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‏‎‏‏‎‎‏‎‎‏‎‏‏‏‏‎‎‏‏‏‎‎‏‏‏‏‎‎‏‎‏‏‎‎‏‎‏‏‎‎‎‎‎‎‏‏‏‏‎‎‎‎Allow‎‏‎‎‏‎"</string>
+    <string name="consent_no" msgid="2640796915611404382">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‏‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‏‎‎‏‏‏‏‎‏‏‏‏‎‏‏‏‎‎‎‎‏‎‎‎‎‏‎‏‏‏‏‎‎Don’t allow‎‏‎‎‏‎"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
index 6b903c6..8dae51c 100644
--- a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Elige un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para que &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; lo administre"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"reloj"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Configura &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; para administrar el dispositivo &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Esta app es necesaria para administrar tu <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
+    <string name="consent_no" msgid="2640796915611404382">"No permitir"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-es/strings.xml b/packages/CompanionDeviceManager/res/values-es/strings.xml
index 0a2906a..a307b61 100644
--- a/packages/CompanionDeviceManager/res/values-es/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Elige un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para gestionarlo con &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"reloj"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Configura &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; para que gestione tu dispositivo &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Se necesita esta aplicación para gestionar tu <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
+    <string name="consent_no" msgid="2640796915611404382">"No permitir"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-et/strings.xml b/packages/CompanionDeviceManager/res/values-et/strings.xml
index 4958a17..2fb2bc4 100644
--- a/packages/CompanionDeviceManager/res/values-et/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-et/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Valige seade <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, mida haldab rakendus &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"seade"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"käekell"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Määrake rakendus &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; haldama teie seadet &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Seda rakendust on vaja teie profiili <xliff:g id="PROFILE_NAME">%1$s</xliff:g> haldamiseks. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Luba"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Ära luba"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-eu/strings.xml b/packages/CompanionDeviceManager/res/values-eu/strings.xml
index 2a61fd5..646f844 100644
--- a/packages/CompanionDeviceManager/res/values-eu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-eu/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Aukeratu &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; aplikazioak kudeatu beharreko <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"gailua"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"erlojua"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Konfiguratu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; kudea dezan"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> kudeatzeko beharrezkoa da aplikazioa. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Eman baimena"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Ez eman baimenik"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-fa/strings.xml b/packages/CompanionDeviceManager/res/values-fa/strings.xml
index 8d10230..69b9647 100644
--- a/packages/CompanionDeviceManager/res/values-fa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fa/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"‏انتخاب <xliff:g id="PROFILE_NAME">%1$s</xliff:g> برای مدیریت کردن با &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>‏&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"دستگاه"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ساعت"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"‏تنظیم &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; برای مدیریت &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"این برنامه برای مدیریت <xliff:g id="PROFILE_NAME">%1$s</xliff:g> شما لازم است. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"مجاز"</string>
+    <string name="consent_no" msgid="2640796915611404382">"مجاز نیست"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-fi/strings.xml b/packages/CompanionDeviceManager/res/values-fi/strings.xml
index cfa03af..b174b8a 100644
--- a/packages/CompanionDeviceManager/res/values-fi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fi/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Valitse <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, jota &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; hallinnoi"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"laite"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"kello"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Valitse &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; laitteen (&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;) ylläpitäjäksi"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Profiilin (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) ylläpitoon tarvitaan tätä sovellusta. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Salli"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Älä salli"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
index d3cfc29..696598d 100644
--- a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Choisissez un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qui sera géré par &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"montre"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Utiliser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pour gérer votre &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Cette application est nécessaire pour gérer votre <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Autoriser"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Ne pas autoriser"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-fr/strings.xml b/packages/CompanionDeviceManager/res/values-fr/strings.xml
index d82e390..787794b 100644
--- a/packages/CompanionDeviceManager/res/values-fr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Sélectionner le/la <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qui sera géré(e) par &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"montre"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Définir &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pour gérer votre &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Cette appli est nécessaire pour gérer votre <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Autoriser"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Ne pas autoriser"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-gl/strings.xml b/packages/CompanionDeviceManager/res/values-gl/strings.xml
index 2a85398..a3efc4c 100644
--- a/packages/CompanionDeviceManager/res/values-gl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gl/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Escolle un perfil (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) para que o xestione a aplicación &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"reloxo"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Configura &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; para que xestione o teu dispositivo &lt;strong&gt;(<xliff:g id="DEVICE_NAME">%2$s</xliff:g>)&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Esta aplicación é necesaria para xestionar o teu perfil (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>). <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Non permitir"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-gu/strings.xml b/packages/CompanionDeviceManager/res/values-gu/strings.xml
index 6f52403..1b0fe1a 100644
--- a/packages/CompanionDeviceManager/res/values-gu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gu/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; દ્વારા મેનેજ કરવા માટે કોઈ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> પસંદ કરો"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ડિવાઇસ"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"સ્માર્ટવૉચ"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"તમારું &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; મેનેજ કરવા માટે, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; સેટ કરો"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"તમારી <xliff:g id="PROFILE_NAME">%1$s</xliff:g> મેનેજ કરવા માટે આ ઍપ જરૂરી છે. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"મંજૂરી આપો"</string>
+    <string name="consent_no" msgid="2640796915611404382">"મંજૂરી આપશો નહીં"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-hi/strings.xml b/packages/CompanionDeviceManager/res/values-hi/strings.xml
index 9af9992..dee30f2 100644
--- a/packages/CompanionDeviceManager/res/values-hi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hi/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"कोई <xliff:g id="PROFILE_NAME">%1$s</xliff:g> चुनें, ताकि उसे &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; की मदद से प्रबंधित किया जा सके"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"डिवाइस"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"स्मार्टवॉच"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; को मैनेज करने के लिए, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; सेट अप करें"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"यह ऐप्लिकेशन, <xliff:g id="PROFILE_NAME">%1$s</xliff:g> मैनेज करने के लिए ज़रूरी है. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"अनुमति दें"</string>
+    <string name="consent_no" msgid="2640796915611404382">"अनुमति न दें"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-hr/strings.xml b/packages/CompanionDeviceManager/res/values-hr/strings.xml
index fe30ec4..bc36521 100644
--- a/packages/CompanionDeviceManager/res/values-hr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hr/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Odaberite profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"satom"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Postavite aplikaciju &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da upravlja vašim uređajem &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Ta je aplikacija potrebna za upravljanje vašim profilom <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Dopusti"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Nemoj dopustiti"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-hu/strings.xml b/packages/CompanionDeviceManager/res/values-hu/strings.xml
index 370d4df..ef50544 100644
--- a/packages/CompanionDeviceManager/res/values-hu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hu/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"A(z) &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; alkalmazással kezelni kívánt <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kiválasztása"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"eszköz"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"óra"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"A(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; alkalmazás beállítva a(z) <xliff:g id="DEVICE_NAME">%2$s</xliff:g> (&lt;strong&gt;&lt;/strong&gt;) kezelésére"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Szükség van erre az alkalmazásra a következő kezeléséhez: <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Engedélyezés"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Tiltás"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-hy/strings.xml b/packages/CompanionDeviceManager/res/values-hy/strings.xml
index fee55d0..103361a 100644
--- a/packages/CompanionDeviceManager/res/values-hy/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hy/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Ընտրեք <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ը, որը պետք է կառավարվի &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; հավելվածի կողմից"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"սարք"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ժամացույց"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Ընտրեք &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածը որպես &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; սարքի կառավարիչ"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Այս հավելվածն անհրաժեշտ է ձեր <xliff:g id="PROFILE_NAME">%1$s</xliff:g> պրոֆիլը կառավարելու համար։ <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Թույլատրել"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Չթույլատրել"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-in/strings.xml b/packages/CompanionDeviceManager/res/values-in/strings.xml
index 498bf2c..225b276 100644
--- a/packages/CompanionDeviceManager/res/values-in/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-in/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Pilih <xliff:g id="PROFILE_NAME">%1$s</xliff:g> untuk dikelola oleh &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"perangkat"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"smartwatch"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Tetapkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; untuk mengelola &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Aplikasi ini diperlukan untuk mengelola <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Izinkan"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Jangan izinkan"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-is/strings.xml b/packages/CompanionDeviceManager/res/values-is/strings.xml
index bd12658..7855a2a 100644
--- a/packages/CompanionDeviceManager/res/values-is/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-is/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Velja <xliff:g id="PROFILE_NAME">%1$s</xliff:g> sem &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; á að stjórna"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"tæki"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"úr"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Veita &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; stjórn á &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Þetta forrit er nauðsynlegt til að hafa umsjón með <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Leyfa"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Ekki leyfa"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-it/strings.xml b/packages/CompanionDeviceManager/res/values-it/strings.xml
index 40d4320..9e503e1 100644
--- a/packages/CompanionDeviceManager/res/values-it/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-it/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Scegli un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> che sia gestito da &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"orologio"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Configura l\'app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; affinché gestisca &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Questa app è necessaria per gestire il tuo <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Consenti"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Non consentire"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-iw/strings.xml b/packages/CompanionDeviceManager/res/values-iw/strings.xml
index 807cdd4..d293fb0 100644
--- a/packages/CompanionDeviceManager/res/values-iw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-iw/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"‏בחירה של <xliff:g id="PROFILE_NAME">%1$s</xliff:g> לניהול באמצעות &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"מכשיר"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"שעון"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"‏הגדרה של &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; לניהול &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"האפליקציה הזו נחוצה כדי לנהל את <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"יש אישור"</string>
+    <string name="consent_no" msgid="2640796915611404382">"אין אישור"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ja/strings.xml b/packages/CompanionDeviceManager/res/values-ja/strings.xml
index 92022be..ac8e2d2 100644
--- a/packages/CompanionDeviceManager/res/values-ja/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ja/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; の管理対象となる<xliff:g id="PROFILE_NAME">%1$s</xliff:g>の選択"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"デバイス"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ウォッチ"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; を管理する &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; の設定"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"このアプリは<xliff:g id="PROFILE_NAME">%1$s</xliff:g>の管理に必要です。<xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"許可"</string>
+    <string name="consent_no" msgid="2640796915611404382">"許可しない"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ka/strings.xml b/packages/CompanionDeviceManager/res/values-ka/strings.xml
index 64a79b4..8b7680e 100644
--- a/packages/CompanionDeviceManager/res/values-ka/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ka/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"აირჩიეთ <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, რომელიც უნდა მართოს &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;-მა"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"მოწყობილობა"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"საათი"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"დააყენეთ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;, რათა მართოთ თქვენი &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"ეს აპი საჭიროა თქვენი <xliff:g id="PROFILE_NAME">%1$s</xliff:g>-ს სამართავად. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"დაშვება"</string>
+    <string name="consent_no" msgid="2640796915611404382">"არ დაიშვას"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-kk/strings.xml b/packages/CompanionDeviceManager/res/values-kk/strings.xml
index edd5c0e..1ad854e 100644
--- a/packages/CompanionDeviceManager/res/values-kk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kk/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; арқылы басқарылатын <xliff:g id="PROFILE_NAME">%1$s</xliff:g> құрылғысын таңдаңыз"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"құрылғы"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"сағат"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; құрылғысын басқаруға рұқсат беріңіз"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Бұл қолданба <xliff:g id="PROFILE_NAME">%1$s</xliff:g> профиліңізді басқару үшін қажет. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Рұқсат беру"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Рұқсат бермеу"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-km/strings.xml b/packages/CompanionDeviceManager/res/values-km/strings.xml
index 36c02de..7231c2d 100644
--- a/packages/CompanionDeviceManager/res/values-km/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-km/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"ជ្រើសរើស <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ដើម្បីឱ្យស្ថិតក្រោម​ការគ្រប់គ្រងរបស់ &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ឧបករណ៍"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"នាឡិកា"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"កំណត់ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ដើម្បីគ្រប់គ្រង &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; របស់អ្នក"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"ត្រូវការកម្មវិធីនេះ ដើម្បីគ្រប់គ្រង <xliff:g id="PROFILE_NAME">%1$s</xliff:g> របស់អ្នក។ <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"អនុញ្ញាត"</string>
+    <string name="consent_no" msgid="2640796915611404382">"កុំអនុញ្ញាត"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-kn/strings.xml b/packages/CompanionDeviceManager/res/values-kn/strings.xml
index 56c1557..6f75328 100644
--- a/packages/CompanionDeviceManager/res/values-kn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kn/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ಮೂಲಕ ನಿರ್ವಹಿಸಬೇಕಾದ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ಸಾಧನ"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ವೀಕ್ಷಿಸಿ"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"ನಿಮ್ಮ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ಅನ್ನು ನಿರ್ವಹಿಸಲು &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಅನ್ನು ಸೆಟ್ ಮಾಡಿ"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"ನಿಮ್ಮ <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. ಅನ್ನು ನಿರ್ವಹಿಸಲು ಈ ಆ್ಯಪ್‌ನ ಅಗತ್ಯವಿದೆ. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"ಅನುಮತಿಸಿ"</string>
+    <string name="consent_no" msgid="2640796915611404382">"ಅನುಮತಿಸಬೇಡಿ"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ko/strings.xml b/packages/CompanionDeviceManager/res/values-ko/strings.xml
index 79c36dd..5b171ea 100644
--- a/packages/CompanionDeviceManager/res/values-ko/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ko/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;에서 관리할 <xliff:g id="PROFILE_NAME">%1$s</xliff:g>을(를) 선택"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"기기"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"시계"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 앱이 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; 기기를 관리하도록 설정"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"이 앱은 <xliff:g id="PROFILE_NAME">%1$s</xliff:g> 프로필을 관리하는 데 필요합니다. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"허용"</string>
+    <string name="consent_no" msgid="2640796915611404382">"허용 안함"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ky/strings.xml b/packages/CompanionDeviceManager/res/values-ky/strings.xml
index 8a90b3d..f7c896b 100644
--- a/packages/CompanionDeviceManager/res/values-ky/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ky/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; тарабынан башкарылсын"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"түзмөк"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"саат"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; түзмөгүңүздү башкаруу үчүн &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосун жөндөңүз"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Бул колдонмо <xliff:g id="PROFILE_NAME">%1$s</xliff:g> профилиңизди башкаруу үчүн керек. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Уруксат берүү"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Уруксат берилбесин"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-lo/strings.xml b/packages/CompanionDeviceManager/res/values-lo/strings.xml
index a6564b3..8ad881f 100644
--- a/packages/CompanionDeviceManager/res/values-lo/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lo/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"ເລືອກ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ເພື່ອໃຫ້ຖືກຈັດການໂດຍ &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ອຸປະກອນ"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ໂມງ"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"ຕັ້ງຄ່າ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ເພື່ອຈັດການ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ຂອງທ່ານ"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"ຕ້ອງໃຊ້ແອັບນີ້ເພື່ອຈັດການ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ຂອງທ່ານ. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"ອະນຸຍາດ"</string>
+    <string name="consent_no" msgid="2640796915611404382">"ບໍ່ອະນຸຍາດ"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-lt/strings.xml b/packages/CompanionDeviceManager/res/values-lt/strings.xml
index 382f1cf..c40d4a7 100644
--- a/packages/CompanionDeviceManager/res/values-lt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lt/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Jūsų <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, kurį valdys &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; (pasirinkite)"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"įrenginys"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"laikrodis"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; tvarkymo naudojant &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; nustatymas"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Ši programa reikalinga norint tvarkyti jūsų <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Leisti"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Neleisti"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-lv/strings.xml b/packages/CompanionDeviceManager/res/values-lv/strings.xml
index 8d70bf7..c842ee1 100644
--- a/packages/CompanionDeviceManager/res/values-lv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lv/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Profila (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) izvēle, ko pārvaldīt lietotnē &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ierīce"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"pulkstenis"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Lietotnes &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; iestatīšana ierīces &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; pārvaldībai"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Šī lietotne ir nepieciešama jūsu profila (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) pārvaldībai. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Atļaut"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Neatļaut"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-mk/strings.xml b/packages/CompanionDeviceManager/res/values-mk/strings.xml
index 5322e98..fdc366e 100644
--- a/packages/CompanionDeviceManager/res/values-mk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mk/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Изберете <xliff:g id="PROFILE_NAME">%1$s</xliff:g> со којшто ќе управува &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"уред"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"часовник"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Поставете &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; за да управувате со вашиот &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Апликацијава е потребна за управување со вашиот <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Дозволи"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Не дозволувај"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ml/strings.xml b/packages/CompanionDeviceManager/res/values-ml/strings.xml
index a9262c7..ae445a3 100644
--- a/packages/CompanionDeviceManager/res/values-ml/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ml/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ഉപയോഗിച്ച് മാനേജ് ചെയ്യുന്നതിന് ഒരു <xliff:g id="PROFILE_NAME">%1$s</xliff:g> തിരഞ്ഞെടുക്കുക"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ഉപകരണം"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"വാച്ച്"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"നിങ്ങളുടെ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; മാനേജ് ചെയ്യുന്നതിന് &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; സജ്ജീകരിക്കുക"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"നിങ്ങളുടെ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> മാനേജ് ചെയ്യാൻ ഈ ആപ്പ് ആവശ്യമാണ്. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"അനുവദിക്കുക"</string>
+    <string name="consent_no" msgid="2640796915611404382">"അനുവദിക്കരുത്"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-mn/strings.xml b/packages/CompanionDeviceManager/res/values-mn/strings.xml
index 3032864..01850e7 100644
--- a/packages/CompanionDeviceManager/res/values-mn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mn/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;-н удирдах<xliff:g id="PROFILE_NAME">%1$s</xliff:g>-г сонгоно уу"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"төхөөрөмж"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"цаг"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Та &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-г удирдахын тулд &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-г тохируулна уу"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Энэ апп таны <xliff:g id="PROFILE_NAME">%1$s</xliff:g>-г удирдахад шаардлагатай. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Зөвшөөрөх"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Бүү зөвшөөр"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-mr/strings.xml b/packages/CompanionDeviceManager/res/values-mr/strings.xml
index 01dae7d..7eea9bf 100644
--- a/packages/CompanionDeviceManager/res/values-mr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mr/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; द्वारे व्यवस्थापित करण्यासाठी <xliff:g id="PROFILE_NAME">%1$s</xliff:g> निवडा"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"डिव्हाइस"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"पाहा"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"तुमचे &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; व्यवस्थापित करण्यासाठी &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; सेट करा"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"तुमची <xliff:g id="PROFILE_NAME">%1$s</xliff:g> प्रोफाइल व्यवस्थापित करण्यासाठी हे ॲप आवश्यक आहे. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"अनुमती द्या"</string>
+    <string name="consent_no" msgid="2640796915611404382">"अनुमती देऊ नका"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ms/strings.xml b/packages/CompanionDeviceManager/res/values-ms/strings.xml
index 4e0f58b..e43a27f 100644
--- a/packages/CompanionDeviceManager/res/values-ms/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ms/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Pilih <xliff:g id="PROFILE_NAME">%1$s</xliff:g> untuk diurus oleh &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"peranti"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"jam tangan"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Tetapkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; untuk mengurus &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; anda"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Apl ini diperlukan untuk menguruskan <xliff:g id="PROFILE_NAME">%1$s</xliff:g> anda. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Benarkan"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Jangan benarkan"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-my/strings.xml b/packages/CompanionDeviceManager/res/values-my/strings.xml
index 050c8ce..1bd3a1d 100644
--- a/packages/CompanionDeviceManager/res/values-my/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-my/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; က စီမံခန့်ခွဲရန် <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ကို ရွေးချယ်ပါ"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"စက်"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"နာရီ"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"သင်၏ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ကို စီမံခန့်ခွဲရန် &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ကို သတ်မှတ်ပါ"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"သင်၏ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ကို စီမံခန့်ခွဲရန် ဤအက်ပ်ကိုလိုအပ်သည်။ <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"ခွင့်ပြုရန်"</string>
+    <string name="consent_no" msgid="2640796915611404382">"ခွင့်မပြုပါ"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-nb/strings.xml b/packages/CompanionDeviceManager/res/values-nb/strings.xml
index a8e2203..e4d247b 100644
--- a/packages/CompanionDeviceManager/res/values-nb/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nb/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Velg <xliff:g id="PROFILE_NAME">%1$s</xliff:g> som skal administreres av &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"klokke"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Velg at &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; skal administrere &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Denne appen kreves for å administrere <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Tillat"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Ikke tillat"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-nl/strings.xml b/packages/CompanionDeviceManager/res/values-nl/strings.xml
index e7e0390..9dc23e7 100644
--- a/packages/CompanionDeviceManager/res/values-nl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nl/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Een <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kiezen om te beheren met &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"apparaat"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"horloge"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; instellen om je &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; te beheren"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Deze app is vereist om je <xliff:g id="PROFILE_NAME">%1$s</xliff:g> te beheren. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Toestaan"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Niet toestaan"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-or/strings.xml b/packages/CompanionDeviceManager/res/values-or/strings.xml
index 1f516fa..4cfe057 100644
--- a/packages/CompanionDeviceManager/res/values-or/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-or/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ଦ୍ୱାରା ପରିଚାଳିତ ହେବା ପାଇଁ ଏକ <xliff:g id="PROFILE_NAME">%1$s</xliff:g>କୁ ବାଛନ୍ତୁ"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ଡିଭାଇସ୍"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ୱାଚ୍"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"ଆପଣଙ୍କ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;କୁ ପରିଚାଳନା କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ ସେଟ୍ କରନ୍ତୁ"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"ଆପଣଙ୍କ <xliff:g id="PROFILE_NAME">%1$s</xliff:g>କୁ ପରିଚାଳନା କରିବା ପାଇଁ ଏହି ଆପ୍ ଆବଶ୍ୟକ। <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"ଅନୁମତି ଦିଅନ୍ତୁ"</string>
+    <string name="consent_no" msgid="2640796915611404382">"ଅନୁମତି ଦିଅନ୍ତୁ ନାହିଁ"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-pl/strings.xml b/packages/CompanionDeviceManager/res/values-pl/strings.xml
index 7adf064..3dbd2f7 100644
--- a/packages/CompanionDeviceManager/res/values-pl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pl/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Wybierz profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, którym ma zarządzać aplikacja &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"urządzenie"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"zegarek"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Skonfiguruj aplikację &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;, aby zarządzała urządzeniem &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Ta aplikacja jest niezbędna do zarządzania profilem <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Zezwól"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Nie zezwalaj"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
index b5ddc6d..91a9fa4 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerenciado pelo app &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Configure o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; para gerenciar seu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Esse app é necessário para gerenciar seu <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Não permitir"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
index c06ac7d..5ad9389 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerido pela app &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Defina a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; para gerir o seu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Esta app é necessária para gerir o seu <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Não permitir"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-pt/strings.xml b/packages/CompanionDeviceManager/res/values-pt/strings.xml
index b5ddc6d..91a9fa4 100644
--- a/packages/CompanionDeviceManager/res/values-pt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerenciado pelo app &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Configure o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; para gerenciar seu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Esse app é necessário para gerenciar seu <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Não permitir"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ro/strings.xml b/packages/CompanionDeviceManager/res/values-ro/strings.xml
index 437e8dc..15f5393 100644
--- a/packages/CompanionDeviceManager/res/values-ro/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ro/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Alegeți un profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> pe care să îl gestioneze &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispozitiv"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ceas"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Setați &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pentru a vă gestiona dispozitivul &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Această aplicație este necesară pentru a gestiona <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Permiteți"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Nu permiteți"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ru/strings.xml b/packages/CompanionDeviceManager/res/values-ru/strings.xml
index d087959..2f79416 100644
--- a/packages/CompanionDeviceManager/res/values-ru/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ru/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Выберите устройство (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), которым будет управлять приложение &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"часы"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Разрешите приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; управлять устройством &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Это приложение необходимо для управления вашим профилем (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>). <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Разрешить"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Запретить"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-si/strings.xml b/packages/CompanionDeviceManager/res/values-si/strings.xml
index 365b6bf..d108a25 100644
--- a/packages/CompanionDeviceManager/res/values-si/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-si/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; මගින් කළමනාකරණය කරනු ලැබීමට <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ක් තෝරන්න"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"උපාංගය"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ඔරලෝසුව"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ඔබගේ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; කළමනාකරණය කිරීමට සකසන්න"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"මෙම යෙදුමට ඔබගේ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> කළමනාකරණය කිරීමට අවශ්‍යයි. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"ඉඩ දෙන්න"</string>
+    <string name="consent_no" msgid="2640796915611404382">"ඉඩ නොදෙන්න"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-sk/strings.xml b/packages/CompanionDeviceManager/res/values-sk/strings.xml
index d5c099a..d53728b 100644
--- a/packages/CompanionDeviceManager/res/values-sk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sk/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Vyberte profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, ktorý bude spravovať aplikácia &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"zariadenie"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"hodinky"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Nastavte aplikáciu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;, aby spravovala zariadenie &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Táto aplikácia sa vyžaduje na správu profilu <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Povoliť"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Nepovoliť"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-sl/strings.xml b/packages/CompanionDeviceManager/res/values-sl/strings.xml
index d855db1..2849210 100644
--- a/packages/CompanionDeviceManager/res/values-sl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sl/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Izbira naprave <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, ki jo bo upravljala aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"naprava"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ura"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Nastavitev aplikacije &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; za upravljanje naprave &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Ta aplikacija je potrebna za upravljanje profila »<xliff:g id="PROFILE_NAME">%1$s</xliff:g>«. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Dovoli"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Ne dovoli"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-sq/strings.xml b/packages/CompanionDeviceManager/res/values-sq/strings.xml
index 7335446..a57835a 100644
--- a/packages/CompanionDeviceManager/res/values-sq/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sq/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Zgjidh një profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> që do të menaxhohet nga &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"pajisja"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ora inteligjente"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Cakto &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; që të menaxhojë pajisjen tënde &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Ky aplikacion nevojitet për të menaxhuar profilin tënd <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Lejo"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Mos lejo"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-sr/strings.xml b/packages/CompanionDeviceManager/res/values-sr/strings.xml
index f3f65e1..0b01cbc 100644
--- a/packages/CompanionDeviceManager/res/values-sr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sr/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Одаберите профил <xliff:g id="PROFILE_NAME">%1$s</xliff:g> којим ће управљати апликација &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"уређај"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"сат"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Подесите апликацију &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; тако да управља уређајем &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Ова апликација је потребна за управљање профилом <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Дозволи"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Не дозволи"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-sv/strings.xml b/packages/CompanionDeviceManager/res/values-sv/strings.xml
index 5741668..f6dcec9 100644
--- a/packages/CompanionDeviceManager/res/values-sv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sv/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Välj en <xliff:g id="PROFILE_NAME">%1$s</xliff:g> för hantering av &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"klocka"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Konfigurera &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; för att hantera din &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Appen behövs för att hantera <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Tillåt"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Tillåt inte"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-sw/strings.xml b/packages/CompanionDeviceManager/res/values-sw/strings.xml
index 357eb4a..0999c5b 100644
--- a/packages/CompanionDeviceManager/res/values-sw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sw/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Chagua <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ili idhibitiwe na &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"kifaa"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"saa"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Weka &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ili udhibiti &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; yako"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Programu hii inahitajika ili udhibiti wasifu wako wa <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Ruhusu"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Usiruhusu"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ta/strings.xml b/packages/CompanionDeviceManager/res/values-ta/strings.xml
index 651d9e2..884d57f 100644
--- a/packages/CompanionDeviceManager/res/values-ta/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ta/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ஆப்ஸ் நிர்வகிக்கக்கூடிய <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ஐத் தேர்ந்தெடுங்கள்"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"சாதனம்"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"வாட்ச்"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"உங்கள் &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; சாதனத்தை நிர்வகிக்க &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அமையுங்கள்"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"உங்கள் <xliff:g id="PROFILE_NAME">%1$s</xliff:g> சுயவிவரத்தை நிர்வகிக்க இந்த ஆப்ஸ் தேவைப்படுகிறது. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"அனுமதி"</string>
+    <string name="consent_no" msgid="2640796915611404382">"அனுமதிக்க வேண்டாம்"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-th/strings.xml b/packages/CompanionDeviceManager/res/values-th/strings.xml
index 557515a..58ebda6 100644
--- a/packages/CompanionDeviceManager/res/values-th/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-th/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"เลือก<xliff:g id="PROFILE_NAME">%1$s</xliff:g>ที่จะให้มีการจัดการโดย &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"อุปกรณ์"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"นาฬิกา"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"ตั้งค่าให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; จัดการ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ของคุณ"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"ต้องใช้แอปนี้ในการจัดการ<xliff:g id="PROFILE_NAME">%1$s</xliff:g>ของคุณ <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"อนุญาต"</string>
+    <string name="consent_no" msgid="2640796915611404382">"ไม่อนุญาต"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-tl/strings.xml b/packages/CompanionDeviceManager/res/values-tl/strings.xml
index 6cbf2e8..1a83284 100644
--- a/packages/CompanionDeviceManager/res/values-tl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tl/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Pumili ng <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para pamahalaan ng &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"relo"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Itakda ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; para pamahalaan ang iyong &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Kinakailangan ang app na ito para pamahalaan ang iyong <xliff:g id="PROFILE_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Payagan"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Huwag payagan"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-tr/strings.xml b/packages/CompanionDeviceManager/res/values-tr/strings.xml
index bc1ab31..b89e874 100644
--- a/packages/CompanionDeviceManager/res/values-tr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tr/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; tarafından yönetilecek bir <xliff:g id="PROFILE_NAME">%1$s</xliff:g> seçin"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"saat"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazınızı yönetmek için &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasını ayarlayın"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Bu uygulama, <xliff:g id="PROFILE_NAME">%1$s</xliff:g> profilinizin yönetilmesi için gereklidir. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"İzin ver"</string>
+    <string name="consent_no" msgid="2640796915611404382">"İzin verme"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-uk/strings.xml b/packages/CompanionDeviceManager/res/values-uk/strings.xml
index 33477c8..2ae852c 100644
--- a/packages/CompanionDeviceManager/res/values-uk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uk/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Виберіть <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, яким керуватиме додаток &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"пристрій"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"годинник"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Налаштуйте додаток &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;, щоб керувати пристроєм &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Цей додаток потрібен, щоб керувати профілем \"<xliff:g id="PROFILE_NAME">%1$s</xliff:g>\". <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Дозволити"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Не дозволяти"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-uz/strings.xml b/packages/CompanionDeviceManager/res/values-uz/strings.xml
index b16db73..5681118 100644
--- a/packages/CompanionDeviceManager/res/values-uz/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uz/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; boshqaradigan <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qurilmasini tanlang"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"qurilma"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"soat"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; qurilmasini boshqarish uchun &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasini sozlang"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Bu ilova <xliff:g id="PROFILE_NAME">%1$s</xliff:g> profilini boshqarish uchun kerak. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Ruxsat"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Ruxsat berilmasin"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-vi/strings.xml b/packages/CompanionDeviceManager/res/values-vi/strings.xml
index 75d2de37..3bbdb57 100644
--- a/packages/CompanionDeviceManager/res/values-vi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-vi/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Chọn một <xliff:g id="PROFILE_NAME">%1$s</xliff:g> sẽ do &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; quản lý"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"thiết bị"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"đồng hồ"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Đặt &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; để quản lý &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; của bạn"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"Cần có ứng dụng này để quản lý <xliff:g id="PROFILE_NAME">%1$s</xliff:g> của bạn. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Cho phép"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Không cho phép"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
index 576f3f4..be29925b 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"選擇由 &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; 管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"裝置"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"手錶"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"設定 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 來管理您的 <xliff:g id="DEVICE_NAME">%2$s</xliff:g> - &lt;strong&gt;&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"必須使用此應用程式,才能管理<xliff:g id="PROFILE_NAME">%1$s</xliff:g>。<xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"允許"</string>
+    <string name="consent_no" msgid="2640796915611404382">"不允許"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
index 8a50658..8044869 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"選擇要讓「<xliff:g id="APP_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"裝置"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"手錶"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;管理你的「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"你必須使用這個應用程式,才能管理<xliff:g id="PROFILE_NAME">%1$s</xliff:g>。<xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"允許"</string>
+    <string name="consent_no" msgid="2640796915611404382">"不允許"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-zu/strings.xml b/packages/CompanionDeviceManager/res/values-zu/strings.xml
index fc3f19d..3ed177c 100644
--- a/packages/CompanionDeviceManager/res/values-zu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zu/strings.xml
@@ -20,12 +20,8 @@
     <string name="chooser_title" msgid="2262294130493605839">"Khetha i-<xliff:g id="PROFILE_NAME">%1$s</xliff:g> ezophathwa yi-&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"idivayisi"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"buka"</string>
-    <!-- no translation found for confirmation_title (814973816731238955) -->
-    <skip />
-    <!-- no translation found for profile_summary (2059360676631420073) -->
-    <skip />
-    <!-- no translation found for consent_yes (8344487259618762872) -->
-    <skip />
-    <!-- no translation found for consent_no (2640796915611404382) -->
-    <skip />
+    <string name="confirmation_title" msgid="814973816731238955">"Setha i-&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukuze iphathe i-<xliff:g id="DEVICE_NAME">%2$s</xliff:g> yakho - &lt;strong&gt;&lt;/strong&gt;"</string>
+    <string name="profile_summary" msgid="2059360676631420073">"I-app iyadingeka ukuphatha i-<xliff:g id="PROFILE_NAME">%1$s</xliff:g> yakho. <xliff:g id="PRIVILEGES_DISCPLAIMER">%2$s</xliff:g>"</string>
+    <string name="consent_yes" msgid="8344487259618762872">"Vumela"</string>
+    <string name="consent_no" msgid="2640796915611404382">"Ungavumeli"</string>
 </resources>
diff --git a/packages/Connectivity/framework/Android.bp b/packages/Connectivity/framework/Android.bp
index 86b85e83..657d5a3 100644
--- a/packages/Connectivity/framework/Android.bp
+++ b/packages/Connectivity/framework/Android.bp
@@ -23,6 +23,26 @@
     default_applicable_licenses: ["frameworks_base_license"],
 }
 
+java_library {
+    name: "framework-connectivity-protos",
+    sdk_version: "module_current",
+    proto: {
+        type: "nano",
+    },
+    srcs: [
+        // TODO: consider moving relevant .proto files directly to the module directory
+        ":framework-javastream-protos",
+    ],
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.tethering",
+    ],
+    jarjar_rules: "jarjar-rules-proto.txt",
+    visibility: [
+        "//visibility:private",
+    ],
+}
+
 filegroup {
     name: "framework-connectivity-internal-sources",
     srcs: [
@@ -63,8 +83,7 @@
     name: "framework-connectivity",
     api_only: true,
     defaults: ["framework-module-defaults"],
-    // TODO: build against module API
-    platform_apis: true,
+    installable: true,
     srcs: [
         ":framework-connectivity-sources",
     ],
@@ -81,5 +100,78 @@
     libs: [
         "unsupportedappusage",
     ],
-    permitted_packages: ["android.net", "com.android.connectivity.aidl"],
+    permitted_packages: ["android.net"],
+}
+
+cc_defaults {
+    name: "libframework-connectivity-defaults",
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+        "-Wthread-safety",
+    ],
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libnativehelper",
+        "libnetd_client",
+    ],
+    header_libs: [
+        "dnsproxyd_protocol_headers",
+    ],
+}
+
+cc_library_static {
+    name: "libconnectivityframeworkutils",
+    defaults: ["libframework-connectivity-defaults"],
+    srcs: [
+        "jni/android_net_NetworkUtils.cpp",
+    ],
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.tethering",
+    ],
+}
+
+cc_library_shared {
+    name: "libframework-connectivity-jni",
+    defaults: ["libframework-connectivity-defaults"],
+    srcs: [
+        "jni/onload.cpp",
+    ],
+    static_libs: ["libconnectivityframeworkutils"],
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.tethering",
+    ],
+}
+
+java_library {
+    name: "framework-connectivity.impl",
+    sdk_version: "module_current",
+    srcs: [
+        ":framework-connectivity-sources",
+    ],
+    aidl: {
+        include_dirs: [
+            "frameworks/base/core/java", // For framework parcelables
+            "frameworks/native/aidl/binder", // For PersistableBundle.aidl
+        ],
+    },
+    libs: [
+        // TODO (b/183097033) remove once module_current includes core_current
+        "stable.core.platform.api.stubs",
+        "framework-tethering",
+        "framework-wifi",
+        "unsupportedappusage",
+    ],
+    static_libs: [
+        "framework-connectivity-protos",
+        "net-utils-device-common",
+    ],
+    jarjar_rules: "jarjar-rules.txt",
+    apex_available: ["com.android.tethering"],
+    installable: true,
+    permitted_packages: ["android.net"],
 }
diff --git a/core/java/android/net/NetworkScore.aidl b/packages/Connectivity/framework/aidl-export/android/net/NetworkScore.aidl
similarity index 100%
rename from core/java/android/net/NetworkScore.aidl
rename to packages/Connectivity/framework/aidl-export/android/net/NetworkScore.aidl
diff --git a/packages/Connectivity/framework/api/current.txt b/packages/Connectivity/framework/api/current.txt
index f22d4b7..e415e01 100644
--- a/packages/Connectivity/framework/api/current.txt
+++ b/packages/Connectivity/framework/api/current.txt
@@ -291,6 +291,7 @@
     ctor public NetworkCapabilities();
     ctor public NetworkCapabilities(android.net.NetworkCapabilities);
     method public int describeContents();
+    method @NonNull public int[] getCapabilities();
     method public int getLinkDownstreamBandwidthKbps();
     method public int getLinkUpstreamBandwidthKbps();
     method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt
index bb29647..5bd01a6 100644
--- a/packages/Connectivity/framework/api/module-lib-current.txt
+++ b/packages/Connectivity/framework/api/module-lib-current.txt
@@ -6,16 +6,29 @@
   }
 
   public class ConnectivityManager {
+    method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void factoryReset();
     method @NonNull @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public java.util.List<android.net.NetworkStateSnapshot> getAllNetworkStateSnapshot();
+    method @Nullable public android.net.ProxyInfo getGlobalProxy();
     method @NonNull public static android.util.Range<java.lang.Integer> getIpSecNetIdRange();
     method @NonNull public static String getPrivateDnsMode(@NonNull android.content.Context);
     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, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
+    method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAcceptPartialConnectivity(@NonNull android.net.Network, boolean, boolean);
+    method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAcceptUnvalidated(@NonNull android.net.Network, boolean, boolean);
+    method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAvoidUnvalidated(@NonNull android.net.Network);
+    method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setGlobalProxy(@Nullable android.net.ProxyInfo);
     method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setProfileNetworkPreference(@NonNull android.os.UserHandle, int, @Nullable java.util.concurrent.Executor, @Nullable Runnable);
     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);
+    method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void startCaptivePortalApp(@NonNull android.net.Network);
+    method public void systemReady();
+    field public static final String ACTION_PROMPT_LOST_VALIDATION = "android.net.action.PROMPT_LOST_VALIDATION";
+    field public static final String ACTION_PROMPT_PARTIAL_CONNECTIVITY = "android.net.action.PROMPT_PARTIAL_CONNECTIVITY";
+    field public static final String ACTION_PROMPT_UNVALIDATED = "android.net.action.PROMPT_UNVALIDATED";
     field public static final String PRIVATE_DNS_MODE_OFF = "off";
     field public static final String PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic";
     field public static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = "hostname";
+    field public static final int PROFILE_NETWORK_PREFERENCE_DEFAULT = 0; // 0x0
+    field public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE = 1; // 0x1
   }
 
   public final class NetworkAgentConfig implements android.os.Parcelable {
@@ -27,9 +40,18 @@
   }
 
   public final class NetworkCapabilities implements android.os.Parcelable {
+    method @Nullable public java.util.Set<android.util.Range<java.lang.Integer>> getUids();
     field public static final int TRANSPORT_TEST = 7; // 0x7
   }
 
+  public static final class NetworkCapabilities.Builder {
+    method @NonNull public android.net.NetworkCapabilities.Builder setUids(@Nullable java.util.Set<android.util.Range<java.lang.Integer>>);
+  }
+
+  public static class NetworkRequest.Builder {
+    method @NonNull public android.net.NetworkRequest.Builder setUids(@Nullable java.util.Set<android.util.Range<java.lang.Integer>>);
+  }
+
   public class ParseException extends java.lang.RuntimeException {
     ctor public ParseException(@NonNull String);
     ctor public ParseException(@NonNull String, @NonNull Throwable);
diff --git a/packages/Connectivity/framework/api/system-current.txt b/packages/Connectivity/framework/api/system-current.txt
index 4dca411..8845225 100644
--- a/packages/Connectivity/framework/api/system-current.txt
+++ b/packages/Connectivity/framework/api/system-current.txt
@@ -18,7 +18,7 @@
     method public long getRefreshTimeMillis();
     method @Nullable public android.net.Uri getUserPortalUrl();
     method public int getUserPortalUrlSource();
-    method @Nullable public String getVenueFriendlyName();
+    method @Nullable public CharSequence getVenueFriendlyName();
     method @Nullable public android.net.Uri getVenueInfoUrl();
     method public int getVenueInfoUrlSource();
     method public boolean isCaptive();
@@ -40,7 +40,7 @@
     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 setVenueFriendlyName(@Nullable CharSequence);
     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);
   }
@@ -67,8 +67,6 @@
     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 PROFILE_NETWORK_PREFERENCE_DEFAULT = 0; // 0x0
-    field public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE = 1; // 0x1
     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
diff --git a/packages/Connectivity/framework/jarjar-rules-proto.txt b/packages/Connectivity/framework/jarjar-rules-proto.txt
new file mode 100644
index 0000000..37b4dec1
--- /dev/null
+++ b/packages/Connectivity/framework/jarjar-rules-proto.txt
@@ -0,0 +1,3 @@
+keep android.net.NetworkCapabilitiesProto
+keep android.net.NetworkProto
+keep android.net.NetworkRequestProto
diff --git a/packages/Connectivity/framework/jarjar-rules.txt b/packages/Connectivity/framework/jarjar-rules.txt
new file mode 100644
index 0000000..0959840
--- /dev/null
+++ b/packages/Connectivity/framework/jarjar-rules.txt
@@ -0,0 +1,10 @@
+rule com.android.net.module.util.** android.net.connectivity.framework.util.@1
+
+# TODO (b/149403767): remove the annotations from net-utils-device-common instead of here
+zap android.annotation.**
+zap com.android.net.module.annotation.**
+zap com.android.internal.annotations.**
+
+rule android.net.NetworkCapabilitiesProto* android.net.connectivity.proto.NetworkCapabilitiesProto@1
+rule android.net.NetworkProto* android.net.connectivity.proto.NetworkProto@1
+rule android.net.NetworkRequestProto* android.net.connectivity.proto.NetworkRequestProto@1
diff --git a/core/jni/android_net_NetworkUtils.cpp b/packages/Connectivity/framework/jni/android_net_NetworkUtils.cpp
similarity index 79%
rename from core/jni/android_net_NetworkUtils.cpp
rename to packages/Connectivity/framework/jni/android_net_NetworkUtils.cpp
index a781a37..19ffe77 100644
--- a/core/jni/android_net_NetworkUtils.cpp
+++ b/packages/Connectivity/framework/jni/android_net_NetworkUtils.cpp
@@ -36,7 +36,6 @@
 #include <utils/misc.h>
 
 #include "NetdClient.h"
-#include "core_jni_helpers.h"
 #include "jni.h"
 
 extern "C" {
@@ -52,6 +51,48 @@
 // FrameworkListener limits the size of commands to 4096 bytes.
 constexpr int MAXCMDSIZE = 4096;
 
+static inline jclass FindClassOrDie(JNIEnv* env, const char* class_name) {
+    jclass clazz = env->FindClass(class_name);
+    LOG_ALWAYS_FATAL_IF(clazz == NULL, "Unable to find class %s", class_name);
+    return clazz;
+}
+
+static inline jmethodID GetMethodIDOrDie(JNIEnv* env, jclass clazz, const char* method_name,
+                                         const char* method_signature) {
+    jmethodID res = env->GetMethodID(clazz, method_name, method_signature);
+    LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find method %s with signature %s", method_name,
+                        method_signature);
+    return res;
+}
+
+template <typename T>
+static inline T MakeGlobalRefOrDie(JNIEnv* env, T in) {
+    jobject res = env->NewGlobalRef(in);
+    LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to create global reference.");
+    return static_cast<T>(res);
+}
+
+static void throwErrnoException(JNIEnv* env, const char* functionName, int error) {
+    ScopedLocalRef<jstring> detailMessage(env, env->NewStringUTF(functionName));
+    if (detailMessage.get() == NULL) {
+        // Not really much we can do here. We're probably dead in the water,
+        // but let's try to stumble on...
+        env->ExceptionClear();
+    }
+    static jclass errnoExceptionClass =
+            MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/system/ErrnoException"));
+
+    static jmethodID errnoExceptionCtor =
+            GetMethodIDOrDie(env, errnoExceptionClass,
+            "<init>", "(Ljava/lang/String;I)V");
+
+    jobject exception = env->NewObject(errnoExceptionClass,
+                                       errnoExceptionCtor,
+                                       detailMessage.get(),
+                                       error);
+    env->Throw(reinterpret_cast<jthrowable>(exception));
+}
+
 static void android_net_utils_attachDropAllBPFFilter(JNIEnv *env, jobject clazz, jobject javaFd)
 {
     struct sock_filter filter_code[] = {
@@ -129,7 +170,7 @@
     int fd = resNetworkQuery(netId, queryname.data(), ns_class, ns_type, flags);
 
     if (fd < 0) {
-        jniThrowErrnoException(env, "resNetworkQuery", -fd);
+        throwErrnoException(env, "resNetworkQuery", -fd);
         return nullptr;
     }
 
@@ -144,7 +185,7 @@
     int fd = resNetworkSend(netId, data, msgLen, flags);
 
     if (fd < 0) {
-        jniThrowErrnoException(env, "resNetworkSend", -fd);
+        throwErrnoException(env, "resNetworkSend", -fd);
         return nullptr;
     }
 
@@ -159,13 +200,13 @@
     int res = resNetworkResult(fd, &rcode, buf.data(), MAXPACKETSIZE);
     jniSetFileDescriptorOfFD(env, javaFd, -1);
     if (res < 0) {
-        jniThrowErrnoException(env, "resNetworkResult", -res);
+        throwErrnoException(env, "resNetworkResult", -res);
         return nullptr;
     }
 
     jbyteArray answer = env->NewByteArray(res);
     if (answer == nullptr) {
-        jniThrowErrnoException(env, "resNetworkResult", ENOMEM);
+        throwErrnoException(env, "resNetworkResult", ENOMEM);
         return nullptr;
     } else {
         env->SetByteArrayRegion(answer, 0, res,
@@ -187,7 +228,7 @@
 static jobject android_net_utils_getDnsNetwork(JNIEnv *env, jobject thiz) {
     unsigned dnsNetId = 0;
     if (int res = getNetworkForDns(&dnsNetId) < 0) {
-        jniThrowErrnoException(env, "getDnsNetId", -res);
+        throwErrnoException(env, "getDnsNetId", -res);
         return nullptr;
     }
     bool privateDnsBypass = dnsNetId & NETID_USE_LOCAL_NAMESERVERS;
@@ -212,7 +253,7 @@
     // Obtain the parameters of the TCP repair window.
     int rc = getsockopt(fd, IPPROTO_TCP, TCP_REPAIR_WINDOW, &trw, &size);
     if (rc == -1) {
-        jniThrowErrnoException(env, "getsockopt : TCP_REPAIR_WINDOW", errno);
+        throwErrnoException(env, "getsockopt : TCP_REPAIR_WINDOW", errno);
         return NULL;
     }
 
@@ -223,7 +264,7 @@
     // should be applied to the window size.
     rc = getsockopt(fd, IPPROTO_TCP, TCP_INFO, &tcpinfo, &tcpinfo_size);
     if (rc == -1) {
-        jniThrowErrnoException(env, "getsockopt : TCP_INFO", errno);
+        throwErrnoException(env, "getsockopt : TCP_INFO", errno);
         return NULL;
     }
 
@@ -260,8 +301,8 @@
 
 int register_android_net_NetworkUtils(JNIEnv* env)
 {
-    return RegisterMethodsOrDie(env, NETUTILS_PKG_NAME, gNetworkUtilMethods,
-                                NELEM(gNetworkUtilMethods));
+    return jniRegisterNativeMethods(env, NETUTILS_PKG_NAME, gNetworkUtilMethods,
+                                    NELEM(gNetworkUtilMethods));
 }
 
 }; // namespace android
diff --git a/packages/Connectivity/framework/jni/onload.cpp b/packages/Connectivity/framework/jni/onload.cpp
new file mode 100644
index 0000000..435f434
--- /dev/null
+++ b/packages/Connectivity/framework/jni/onload.cpp
@@ -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.
+ */
+
+#include <nativehelper/JNIHelp.h>
+#include <log/log.h>
+
+namespace android {
+
+int register_android_net_NetworkUtils(JNIEnv* env);
+
+extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
+    JNIEnv *env;
+    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+        ALOGE("GetEnv failed");
+        return JNI_ERR;
+    }
+
+    if (register_android_net_NetworkUtils(env) < 0) {
+        return JNI_ERR;
+    }
+
+    return JNI_VERSION_1_6;
+}
+
+};
\ No newline at end of file
diff --git a/packages/Connectivity/framework/src/android/net/CaptivePortalData.java b/packages/Connectivity/framework/src/android/net/CaptivePortalData.java
index eafda4d..53aa1b9 100644
--- a/packages/Connectivity/framework/src/android/net/CaptivePortalData.java
+++ b/packages/Connectivity/framework/src/android/net/CaptivePortalData.java
@@ -65,7 +65,7 @@
 
     private CaptivePortalData(long refreshTimeMillis, Uri userPortalUrl, Uri venueInfoUrl,
             boolean isSessionExtendable, long byteLimit, long expiryTimeMillis, boolean captive,
-            String venueFriendlyName, int venueInfoUrlSource, int userPortalUrlSource) {
+            CharSequence venueFriendlyName, int venueInfoUrlSource, int userPortalUrlSource) {
         mRefreshTimeMillis = refreshTimeMillis;
         mUserPortalUrl = userPortalUrl;
         mVenueInfoUrl = venueInfoUrl;
@@ -73,7 +73,7 @@
         mByteLimit = byteLimit;
         mExpiryTimeMillis = expiryTimeMillis;
         mCaptive = captive;
-        mVenueFriendlyName = venueFriendlyName;
+        mVenueFriendlyName = venueFriendlyName == null ? null : venueFriendlyName.toString();
         mVenueInfoUrlSource = venueInfoUrlSource;
         mUserPortalUrlSource = userPortalUrlSource;
     }
@@ -114,7 +114,7 @@
         private long mBytesRemaining = -1;
         private long mExpiryTime = -1;
         private boolean mCaptive;
-        private String mVenueFriendlyName;
+        private CharSequence mVenueFriendlyName;
         private @CaptivePortalDataSource int mVenueInfoUrlSource = CAPTIVE_PORTAL_DATA_SOURCE_OTHER;
         private @CaptivePortalDataSource int mUserPortalUrlSource =
                 CAPTIVE_PORTAL_DATA_SOURCE_OTHER;
@@ -228,7 +228,7 @@
          * Set the venue friendly name.
          */
         @NonNull
-        public Builder setVenueFriendlyName(@Nullable String venueFriendlyName) {
+        public Builder setVenueFriendlyName(@Nullable CharSequence venueFriendlyName) {
             mVenueFriendlyName = venueFriendlyName;
             return this;
         }
@@ -321,7 +321,7 @@
      * Get the venue friendly name
      */
     @Nullable
-    public String getVenueFriendlyName() {
+    public CharSequence getVenueFriendlyName() {
         return mVenueFriendlyName;
     }
 
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityDiagnosticsManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityDiagnosticsManager.java
index 5234494..3598ebc 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityDiagnosticsManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityDiagnosticsManager.java
@@ -28,7 +28,6 @@
 import android.os.RemoteException;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -70,8 +69,8 @@
 
     /** @hide */
     public ConnectivityDiagnosticsManager(Context context, IConnectivityManager service) {
-        mContext = Preconditions.checkNotNull(context, "missing context");
-        mService = Preconditions.checkNotNull(service, "missing IConnectivityManager");
+        mContext = Objects.requireNonNull(context, "missing context");
+        mService = Objects.requireNonNull(service, "missing IConnectivityManager");
     }
 
     /** @hide */
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
index ba5eb10..f8a0e4e 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
@@ -16,6 +16,8 @@
 package android.net;
 
 import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_DEFAULT_MODE;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE;
 import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST;
 import static android.net.NetworkRequest.Type.LISTEN;
 import static android.net.NetworkRequest.Type.LISTEN_FOR_BEST;
@@ -23,8 +25,6 @@
 import static android.net.NetworkRequest.Type.TRACK_DEFAULT;
 import static android.net.NetworkRequest.Type.TRACK_SYSTEM_DEFAULT;
 import static android.net.QosCallback.QosCallbackRegistrationException;
-import static android.provider.Settings.Global.PRIVATE_DNS_DEFAULT_MODE;
-import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
 
 import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
@@ -62,7 +62,6 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
-import android.os.ServiceManager;
 import android.os.ServiceSpecificException;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -74,9 +73,7 @@
 import android.util.Range;
 import android.util.SparseIntArray;
 
-import com.android.connectivity.aidl.INetworkAgent;
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
 
 import libcore.net.event.NetworkEventDispatcher;
 
@@ -426,7 +423,8 @@
      *
      * @hide
      */
-    public static final String ACTION_PROMPT_UNVALIDATED = "android.net.conn.PROMPT_UNVALIDATED";
+    @SystemApi(client = MODULE_LIBRARIES)
+    public static final String ACTION_PROMPT_UNVALIDATED = "android.net.action.PROMPT_UNVALIDATED";
 
     /**
      * Action used to display a dialog that asks the user whether to avoid a network that is no
@@ -434,8 +432,9 @@
      *
      * @hide
      */
+    @SystemApi(client = MODULE_LIBRARIES)
     public static final String ACTION_PROMPT_LOST_VALIDATION =
-            "android.net.conn.PROMPT_LOST_VALIDATION";
+            "android.net.action.PROMPT_LOST_VALIDATION";
 
     /**
      * Action used to display a dialog that asks the user whether to stay connected to a network
@@ -444,8 +443,9 @@
      *
      * @hide
      */
+    @SystemApi(client = MODULE_LIBRARIES)
     public static final String ACTION_PROMPT_PARTIAL_CONNECTIVITY =
-            "android.net.conn.PROMPT_PARTIAL_CONNECTIVITY";
+            "android.net.action.PROMPT_PARTIAL_CONNECTIVITY";
 
     /**
      * Invalid tethering type.
@@ -842,7 +842,6 @@
 
     private final Context mContext;
 
-    private INetworkPolicyManager mNPManager;
     private final TetheringManager mTetheringManager;
 
     /**
@@ -915,8 +914,8 @@
 
     /**
      * @hide
-     * TODO: Expose for SystemServer when becomes a module.
      */
+    @SystemApi(client = MODULE_LIBRARIES)
     public void systemReady() {
         try {
             mService.systemReady();
@@ -975,7 +974,7 @@
      * Specify that the traffic for this user should by follow the default rules.
      * @hide
      */
-    @SystemApi
+    @SystemApi(client = MODULE_LIBRARIES)
     public static final int PROFILE_NETWORK_PREFERENCE_DEFAULT = 0;
 
     /**
@@ -985,7 +984,7 @@
      * if no such network is available.
      * @hide
      */
-    @SystemApi
+    @SystemApi(client = MODULE_LIBRARIES)
     public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE = 1;
 
     /** @hide */
@@ -1777,7 +1776,9 @@
         // Map from type to transports.
         final int NOT_FOUND = -1;
         final int transport = sLegacyTypeToTransport.get(type, NOT_FOUND);
-        Preconditions.checkArgument(transport != NOT_FOUND, "unknown legacy type: " + type);
+        if (transport == NOT_FOUND) {
+            throw new IllegalArgumentException("unknown legacy type: " + type);
+        }
         nc.addTransportType(transport);
 
         // Map from type to capabilities.
@@ -1882,8 +1883,8 @@
         }
 
         private PacketKeepalive(Network network, PacketKeepaliveCallback callback) {
-            Preconditions.checkNotNull(network, "network cannot be null");
-            Preconditions.checkNotNull(callback, "callback cannot be null");
+            Objects.requireNonNull(network, "network cannot be null");
+            Objects.requireNonNull(callback, "callback cannot be null");
             mNetwork = network;
             mExecutor = Executors.newSingleThreadExecutor();
             mCallback = new ISocketKeepaliveCallback.Stub() {
@@ -2258,7 +2259,9 @@
      */
     public void removeDefaultNetworkActiveListener(@NonNull OnNetworkActiveListener l) {
         INetworkActivityListener rl = mNetworkActivityListeners.get(l);
-        Preconditions.checkArgument(rl != null, "Listener was not registered.");
+        if (rl == null) {
+            throw new IllegalArgumentException("Listener was not registered.");
+        }
         try {
             mService.registerNetworkActivityListener(rl);
         } catch (RemoteException e) {
@@ -2286,8 +2289,8 @@
      * {@hide}
      */
     public ConnectivityManager(Context context, IConnectivityManager service) {
-        mContext = Preconditions.checkNotNull(context, "missing context");
-        mService = Preconditions.checkNotNull(service, "missing IConnectivityManager");
+        mContext = Objects.requireNonNull(context, "missing context");
+        mService = Objects.requireNonNull(service, "missing IConnectivityManager");
         mTetheringManager = (TetheringManager) mContext.getSystemService(Context.TETHERING_SERVICE);
         sInstance = this;
     }
@@ -2554,7 +2557,7 @@
     @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
     public void startTethering(int type, boolean showProvisioningUi,
             final OnStartTetheringCallback callback, Handler handler) {
-        Preconditions.checkNotNull(callback, "OnStartTetheringCallback cannot be null.");
+        Objects.requireNonNull(callback, "OnStartTetheringCallback cannot be null.");
 
         final Executor executor = new Executor() {
             @Override
@@ -2647,7 +2650,7 @@
     public void registerTetheringEventCallback(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull final OnTetheringEventCallback callback) {
-        Preconditions.checkNotNull(callback, "OnTetheringEventCallback cannot be null.");
+        Objects.requireNonNull(callback, "OnTetheringEventCallback cannot be null.");
 
         final TetheringEventCallback tetherCallback =
                 new TetheringEventCallback() {
@@ -2945,7 +2948,7 @@
     public void getLatestTetheringEntitlementResult(int type, boolean showEntitlementUi,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull final OnTetheringEntitlementResultListener listener) {
-        Preconditions.checkNotNull(listener, "TetheringEntitlementResultListener cannot be null.");
+        Objects.requireNonNull(listener, "TetheringEntitlementResultListener cannot be null.");
         ResultReceiver wrappedListener = new ResultReceiver(null) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -3038,8 +3041,9 @@
      *        HTTP proxy.  A {@code null} value will clear the global HTTP proxy.
      * @hide
      */
+    @SystemApi(client = MODULE_LIBRARIES)
     @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
-    public void setGlobalProxy(ProxyInfo p) {
+    public void setGlobalProxy(@Nullable ProxyInfo p) {
         try {
             mService.setGlobalProxy(p);
         } catch (RemoteException e) {
@@ -3054,6 +3058,8 @@
      *        if no global HTTP proxy is set.
      * @hide
      */
+    @SystemApi(client = MODULE_LIBRARIES)
+    @Nullable
     public ProxyInfo getGlobalProxy() {
         try {
             return mService.getGlobalProxy();
@@ -3315,7 +3321,9 @@
         }
 
         public NetworkCallback(@Flag int flags) {
-            Preconditions.checkArgument((flags & VALID_FLAGS) == flags);
+            if ((flags & VALID_FLAGS) != flags) {
+                throw new IllegalArgumentException("Invalid flags");
+            }
             mFlags = flags;
         }
 
@@ -3601,7 +3609,7 @@
         }
 
         CallbackHandler(Handler handler) {
-            this(Preconditions.checkNotNull(handler, "Handler cannot be null.").getLooper());
+            this(Objects.requireNonNull(handler, "Handler cannot be null.").getLooper());
         }
 
         @Override
@@ -3699,9 +3707,9 @@
             int timeoutMs, NetworkRequest.Type reqType, int legacyType, CallbackHandler handler) {
         printStackTrace();
         checkCallbackNotNull(callback);
-        Preconditions.checkArgument(
-                reqType == TRACK_DEFAULT || reqType == TRACK_SYSTEM_DEFAULT || need != null,
-                "null NetworkCapabilities");
+        if (reqType != TRACK_DEFAULT && reqType != TRACK_SYSTEM_DEFAULT && need == null) {
+            throw new IllegalArgumentException("null NetworkCapabilities");
+        }
         final NetworkRequest request;
         final String callingPackageName = mContext.getOpPackageName();
         try {
@@ -4048,15 +4056,17 @@
     }
 
     private static void checkPendingIntentNotNull(PendingIntent intent) {
-        Preconditions.checkNotNull(intent, "PendingIntent cannot be null.");
+        Objects.requireNonNull(intent, "PendingIntent cannot be null.");
     }
 
     private static void checkCallbackNotNull(NetworkCallback callback) {
-        Preconditions.checkNotNull(callback, "null NetworkCallback");
+        Objects.requireNonNull(callback, "null NetworkCallback");
     }
 
     private static void checkTimeout(int timeoutMs) {
-        Preconditions.checkArgumentPositive(timeoutMs, "timeoutMs must be strictly positive.");
+        if (timeoutMs <= 0) {
+            throw new IllegalArgumentException("timeoutMs must be strictly positive.");
+        }
     }
 
     /**
@@ -4336,8 +4346,9 @@
         // Find all requests associated to this callback and stop callback triggers immediately.
         // Callback is reusable immediately. http://b/20701525, http://b/35921499.
         synchronized (sCallbacks) {
-            Preconditions.checkArgument(networkCallback.networkRequest != null,
-                    "NetworkCallback was not registered");
+            if (networkCallback.networkRequest == null) {
+                throw new IllegalArgumentException("NetworkCallback was not registered");
+            }
             if (networkCallback.networkRequest == ALREADY_UNREGISTERED) {
                 Log.d(TAG, "NetworkCallback was already unregistered");
                 return;
@@ -4388,8 +4399,13 @@
      *
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
-    public void setAcceptUnvalidated(Network network, boolean accept, boolean always) {
+    @SystemApi(client = MODULE_LIBRARIES)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD,
+            android.Manifest.permission.NETWORK_STACK,
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
+    public void setAcceptUnvalidated(@NonNull Network network, boolean accept, boolean always) {
         try {
             mService.setAcceptUnvalidated(network, accept, always);
         } catch (RemoteException e) {
@@ -4411,8 +4427,14 @@
      *
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
-    public void setAcceptPartialConnectivity(Network network, boolean accept, boolean always) {
+    @SystemApi(client = MODULE_LIBRARIES)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD,
+            android.Manifest.permission.NETWORK_STACK,
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
+    public void setAcceptPartialConnectivity(@NonNull Network network, boolean accept,
+            boolean always) {
         try {
             mService.setAcceptPartialConnectivity(network, accept, always);
         } catch (RemoteException e) {
@@ -4430,8 +4452,13 @@
      *
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
-    public void setAvoidUnvalidated(Network network) {
+    @SystemApi(client = MODULE_LIBRARIES)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD,
+            android.Manifest.permission.NETWORK_STACK,
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
+    public void setAvoidUnvalidated(@NonNull Network network) {
         try {
             mService.setAvoidUnvalidated(network);
         } catch (RemoteException e) {
@@ -4442,12 +4469,20 @@
     /**
      * Requests that the system open the captive portal app on the specified network.
      *
+     * <p>This is to be used on networks where a captive portal was detected, as per
+     * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}.
+     *
      * @param network The network to log into.
      *
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
-    public void startCaptivePortalApp(Network network) {
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_STACK,
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
+    })
+    public void startCaptivePortalApp(@NonNull Network network) {
         try {
             mService.startCaptivePortalApp(network);
         } catch (RemoteException e) {
@@ -4561,7 +4596,10 @@
      * Resets all connectivity manager settings back to factory defaults.
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+    @SystemApi(client = MODULE_LIBRARIES)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
     public void factoryReset() {
         try {
             mService.factoryReset();
@@ -4639,7 +4677,7 @@
                 Log.e(TAG, "Can't set proxy properties", e);
             }
             // Must flush DNS cache as new network may have different DNS resolutions.
-            InetAddress.clearDnsCache();
+            InetAddressCompat.clearDnsCache();
             // Must flush socket pool as idle sockets will be bound to previous network and may
             // cause subsequent fetches to be performed on old network.
             NetworkEventDispatcher.getInstance().onNetworkConfigurationChanged();
@@ -4764,17 +4802,6 @@
     public @interface RestrictBackgroundStatus {
     }
 
-    private INetworkPolicyManager getNetworkPolicyManager() {
-        synchronized (this) {
-            if (mNPManager != null) {
-                return mNPManager;
-            }
-            mNPManager = INetworkPolicyManager.Stub.asInterface(ServiceManager
-                    .getService(Context.NETWORK_POLICY_SERVICE));
-            return mNPManager;
-        }
-    }
-
     /**
      * Determines if the calling application is subject to metered network restrictions while
      * running on background.
@@ -4785,7 +4812,7 @@
      */
     public @RestrictBackgroundStatus int getRestrictBackgroundStatus() {
         try {
-            return getNetworkPolicyManager().getRestrictBackgroundByCaller();
+            return mService.getRestrictBackgroundStatusByCaller();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/services/core/java/com/android/server/connectivity/ConnectivityResources.java b/packages/Connectivity/framework/src/android/net/ConnectivityResources.java
similarity index 69%
rename from services/core/java/com/android/server/connectivity/ConnectivityResources.java
rename to packages/Connectivity/framework/src/android/net/ConnectivityResources.java
index 45cf21e..18f0de0 100644
--- a/services/core/java/com/android/server/connectivity/ConnectivityResources.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityResources.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.connectivity;
+package android.net;
 
 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
 
@@ -27,13 +27,14 @@
 import android.content.res.Resources;
 import android.util.Log;
 
-import com.android.server.ConnectivityService;
+import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.List;
 
 /**
- * Utility to obtain the {@link ConnectivityService} {@link Resources}, in the
+ * Utility to obtain the {@link com.android.server.ConnectivityService} {@link Resources}, in the
  * ServiceConnectivityResources APK.
+ * @hide
  */
 public class ConnectivityResources {
     private static final String RESOURCES_APK_INTENT =
@@ -44,18 +45,35 @@
     private final Context mContext;
 
     @Nullable
-    private Resources mResources = null;
+    private Context mResourcesContext = null;
+
+    @Nullable
+    private static Context sTestResourcesContext = null;
 
     public ConnectivityResources(Context context) {
         mContext = context;
     }
 
     /**
-     * Get the {@link Resources} of the ServiceConnectivityResources APK.
+     * Convenience method to mock all resources for the duration of a test.
+     *
+     * Call with a null context to reset after the test.
      */
-    public synchronized Resources get() {
-        if (mResources != null) {
-            return mResources;
+    @VisibleForTesting
+    public static void setResourcesContextForTest(@Nullable Context testContext) {
+        sTestResourcesContext = testContext;
+    }
+
+    /**
+     * Get the {@link Context} of the resources package.
+     */
+    public synchronized Context getResourcesContext() {
+        if (sTestResourcesContext != null) {
+            return sTestResourcesContext;
+        }
+
+        if (mResourcesContext != null) {
+            return mResourcesContext;
         }
 
         final List<ResolveInfo> pkgs = mContext.getPackageManager()
@@ -77,7 +95,14 @@
             throw new IllegalStateException("Resolved package not found", e);
         }
 
-        mResources = pkgContext.getResources();
-        return mResources;
+        mResourcesContext = pkgContext;
+        return pkgContext;
+    }
+
+    /**
+     * Get the {@link Resources} of the ServiceConnectivityResources APK.
+     */
+    public Resources get() {
+        return getResourcesContext().getResources();
     }
 }
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java b/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java
index d454365..bbd8393 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java
@@ -16,6 +16,11 @@
 
 package android.net;
 
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * A manager class for connectivity module settings.
  *
@@ -25,6 +30,196 @@
 
     private ConnectivitySettingsManager() {}
 
+    /** Data activity timeout settings */
+
+    /**
+     * Inactivity timeout to track mobile data activity.
+     *
+     * If set to a positive integer, it indicates the inactivity timeout value in seconds to
+     * infer the data activity of mobile network. After a period of no activity on mobile
+     * networks with length specified by the timeout, an {@code ACTION_DATA_ACTIVITY_CHANGE}
+     * intent is fired to indicate a transition of network status from "active" to "idle". Any
+     * subsequent activity on mobile networks triggers the firing of {@code
+     * ACTION_DATA_ACTIVITY_CHANGE} intent indicating transition from "idle" to "active".
+     *
+     * Network activity refers to transmitting or receiving data on the network interfaces.
+     *
+     * Tracking is disabled if set to zero or negative value.
+     */
+    public static final String DATA_ACTIVITY_TIMEOUT_MOBILE = "data_activity_timeout_mobile";
+
+    /**
+     * Timeout to tracking Wifi data activity. Same as {@code DATA_ACTIVITY_TIMEOUT_MOBILE}
+     * but for Wifi network.
+     */
+    public static final String DATA_ACTIVITY_TIMEOUT_WIFI = "data_activity_timeout_wifi";
+
+    /** Dns resolver settings */
+
+    /**
+     * Sample validity in seconds to configure for the system DNS resolver.
+     */
+    public static final String DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS =
+            "dns_resolver_sample_validity_seconds";
+
+    /**
+     * Success threshold in percent for use with the system DNS resolver.
+     */
+    public static final String DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT =
+            "dns_resolver_success_threshold_percent";
+
+    /**
+     * Minimum number of samples needed for statistics to be considered meaningful in the
+     * system DNS resolver.
+     */
+    public static final String DNS_RESOLVER_MIN_SAMPLES = "dns_resolver_min_samples";
+
+    /**
+     * Maximum number taken into account for statistics purposes in the system DNS resolver.
+     */
+    public static final String DNS_RESOLVER_MAX_SAMPLES = "dns_resolver_max_samples";
+
+    /** Network switch notification settings */
+
+    /**
+     * The maximum number of notifications shown in 24 hours when switching networks.
+     */
+    public static final String NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT =
+            "network_switch_notification_daily_limit";
+
+    /**
+     * The minimum time in milliseconds between notifications when switching networks.
+     */
+    public static final String NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS =
+            "network_switch_notification_rate_limit_millis";
+
+    /** Captive portal settings */
+
+    /**
+     * The URL used for HTTP captive portal detection upon a new connection.
+     * A 204 response code from the server is used for validation.
+     */
+    public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url";
+
+    /**
+     * What to do when connecting a network that presents a captive portal.
+     * Must be one of the CAPTIVE_PORTAL_MODE_* constants above.
+     *
+     * The default for this setting is CAPTIVE_PORTAL_MODE_PROMPT.
+     */
+    public static final String CAPTIVE_PORTAL_MODE = "captive_portal_mode";
+
+    /**
+     * Don't attempt to detect captive portals.
+     */
+    public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0;
+
+    /**
+     * When detecting a captive portal, display a notification that
+     * prompts the user to sign in.
+     */
+    public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1;
+
+    /**
+     * When detecting a captive portal, immediately disconnect from the
+     * network and do not reconnect to that network in the future.
+     */
+    public static final int CAPTIVE_PORTAL_MODE_AVOID = 2;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {
+            CAPTIVE_PORTAL_MODE_IGNORE,
+            CAPTIVE_PORTAL_MODE_PROMPT,
+            CAPTIVE_PORTAL_MODE_AVOID,
+    })
+    public @interface CaptivePortalMode {}
+
+    /** Global http proxy settings */
+
+    /**
+     * Host name for global http proxy. Set via ConnectivityManager.
+     */
+    public static final String GLOBAL_HTTP_PROXY_HOST = "global_http_proxy_host";
+
+    /**
+     * Integer host port for global http proxy. Set via ConnectivityManager.
+     */
+    public static final String GLOBAL_HTTP_PROXY_PORT = "global_http_proxy_port";
+
+    /**
+     * Exclusion list for global proxy. This string contains a list of
+     * comma-separated domains where the global proxy does not apply.
+     * Domains should be listed in a comma- separated list. Example of
+     * acceptable formats: ".domain1.com,my.domain2.com" Use
+     * ConnectivityManager to set/get.
+     */
+    public static final String GLOBAL_HTTP_PROXY_EXCLUSION_LIST =
+            "global_http_proxy_exclusion_list";
+
+    /**
+     * The location PAC File for the proxy.
+     */
+    public static final String GLOBAL_HTTP_PROXY_PAC = "global_proxy_pac_url";
+
+    /** Private dns settings */
+
+    /**
+     * The requested Private DNS mode (string), and an accompanying specifier (string).
+     *
+     * Currently, the specifier holds the chosen provider name when the mode requests
+     * a specific provider. It may be used to store the provider name even when the
+     * mode changes so that temporarily disabling and re-enabling the specific
+     * provider mode does not necessitate retyping the provider hostname.
+     */
+    public static final String PRIVATE_DNS_MODE = "private_dns_mode";
+
+    /**
+     * The specific Private DNS provider name.
+     */
+    public static final String PRIVATE_DNS_SPECIFIER = "private_dns_specifier";
+
+    /**
+     * Forced override of the default mode (hardcoded as "automatic", nee "opportunistic").
+     * This allows changing the default mode without effectively disabling other modes,
+     * all of which require explicit user action to enable/configure. See also b/79719289.
+     *
+     * Value is a string, suitable for assignment to PRIVATE_DNS_MODE above.
+     */
+    public static final String PRIVATE_DNS_DEFAULT_MODE = "private_dns_default_mode";
+
+    /** Other settings */
+
+    /**
+     * The number of milliseconds to hold on to a PendingIntent based request. This delay gives
+     * the receivers of the PendingIntent an opportunity to make a new network request before
+     * the Network satisfying the request is potentially removed.
+     */
+    public static final String CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS =
+            "connectivity_release_pending_intent_delay_ms";
+
+    /**
+     * Whether the mobile data connection should remain active even when higher
+     * priority networks like WiFi are active, to help make network switching faster.
+     *
+     * See ConnectivityService for more info.
+     *
+     * (0 = disabled, 1 = enabled)
+     */
+    public static final String MOBILE_DATA_ALWAYS_ON = "mobile_data_always_on";
+
+    /**
+     * Whether the wifi data connection should remain active even when higher
+     * priority networks like Ethernet are active, to keep both networks.
+     * In the case where higher priority networks are connected, wifi will be
+     * unused unless an application explicitly requests to use it.
+     *
+     * See ConnectivityService for more info.
+     *
+     * (0 = disabled, 1 = enabled)
+     */
+    public static final String WIFI_ALWAYS_REQUESTED = "wifi_always_requested";
+
     /**
      * Whether to automatically switch away from wifi networks that lose Internet access.
      * Only meaningful if config_networkAvoidBadWifi is set to 0, otherwise the system always
diff --git a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
index d83cc16..3300fa8 100644
--- a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
+++ b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
@@ -20,6 +20,7 @@
 import android.net.ConnectionInfo;
 import android.net.ConnectivityDiagnosticsManager;
 import android.net.IConnectivityDiagnosticsCallback;
+import android.net.INetworkAgent;
 import android.net.IOnCompleteListener;
 import android.net.INetworkActivityListener;
 import android.net.IQosCallback;
@@ -45,8 +46,6 @@
 import android.os.ResultReceiver;
 import android.os.UserHandle;
 
-import com.android.connectivity.aidl.INetworkAgent;
-
 /**
  * Interface that answers queries about, and allows changing, the
  * state of network connectivity.
@@ -220,4 +219,6 @@
 
     void setProfileNetworkPreference(in UserHandle profile, int preference,
             in IOnCompleteListener listener);
+
+    int getRestrictBackgroundStatusByCaller();
 }
diff --git a/packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgent.aidl b/packages/Connectivity/framework/src/android/net/INetworkAgent.aidl
similarity index 94%
rename from packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgent.aidl
rename to packages/Connectivity/framework/src/android/net/INetworkAgent.aidl
index 64b5567..1f66e18 100644
--- a/packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgent.aidl
+++ b/packages/Connectivity/framework/src/android/net/INetworkAgent.aidl
@@ -13,13 +13,13 @@
  * See the License for the specific language governing perNmissions and
  * limitations under the License.
  */
-package com.android.connectivity.aidl;
+package android.net;
 
 import android.net.NattKeepalivePacketData;
 import android.net.QosFilterParcelable;
 import android.net.TcpKeepalivePacketData;
 
-import com.android.connectivity.aidl.INetworkAgentRegistry;
+import android.net.INetworkAgentRegistry;
 
 /**
  * Interface to notify NetworkAgent of connectivity events.
diff --git a/packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgentRegistry.aidl b/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl
similarity index 97%
rename from packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgentRegistry.aidl
rename to packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl
index 18d26a7..c5464d3 100644
--- a/packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgentRegistry.aidl
+++ b/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl
@@ -13,7 +13,7 @@
  * See the License for the specific language governing perNmissions and
  * limitations under the License.
  */
-package com.android.connectivity.aidl;
+package android.net;
 
 import android.net.LinkProperties;
 import android.net.Network;
diff --git a/core/java/android/net/IOnCompleteListener.aidl b/packages/Connectivity/framework/src/android/net/IOnCompleteListener.aidl
similarity index 100%
rename from core/java/android/net/IOnCompleteListener.aidl
rename to packages/Connectivity/framework/src/android/net/IOnCompleteListener.aidl
diff --git a/packages/Connectivity/framework/src/android/net/InetAddressCompat.java b/packages/Connectivity/framework/src/android/net/InetAddressCompat.java
new file mode 100644
index 0000000..6b7e75c
--- /dev/null
+++ b/packages/Connectivity/framework/src/android/net/InetAddressCompat.java
@@ -0,0 +1,88 @@
+/*
+ * 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.util.Log;
+
+import java.lang.reflect.InvocationTargetException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * Compatibility utility for InetAddress core platform APIs.
+ *
+ * Connectivity has access to such APIs, but they are not part of the module_current stubs yet
+ * (only core_current). Most stable core platform APIs are included manually in the connectivity
+ * build rules, but because InetAddress is also part of the base java SDK that is earlier on the
+ * classpath, the extra core platform APIs are not seen.
+ *
+ * TODO (b/183097033): remove this utility as soon as core_current is part of module_current
+ * @hide
+ */
+public class InetAddressCompat {
+
+    /**
+     * @see InetAddress#clearDnsCache()
+     */
+    public static void clearDnsCache() {
+        try {
+            InetAddress.class.getMethod("clearDnsCache").invoke(null);
+        } catch (InvocationTargetException e) {
+            if (e.getCause() instanceof RuntimeException) {
+                throw (RuntimeException) e.getCause();
+            }
+            throw new IllegalStateException("Unknown InvocationTargetException", e.getCause());
+        } catch (IllegalAccessException | NoSuchMethodException e) {
+            Log.wtf(InetAddressCompat.class.getSimpleName(), "Error clearing DNS cache", e);
+        }
+    }
+
+    /**
+     * @see InetAddress#getAllByNameOnNet(String, int)
+     */
+    public static InetAddress[] getAllByNameOnNet(String host, int netId) throws
+            UnknownHostException {
+        return (InetAddress[]) callGetByNameMethod("getAllByNameOnNet", host, netId);
+    }
+
+    /**
+     * @see InetAddress#getByNameOnNet(String, int)
+     */
+    public static InetAddress getByNameOnNet(String host, int netId) throws
+            UnknownHostException {
+        return (InetAddress) callGetByNameMethod("getByNameOnNet", host, netId);
+    }
+
+    private static Object callGetByNameMethod(String method, String host, int netId)
+            throws UnknownHostException {
+        try {
+            return InetAddress.class.getMethod(method, String.class, int.class)
+                    .invoke(null, host, netId);
+        } catch (InvocationTargetException e) {
+            if (e.getCause() instanceof UnknownHostException) {
+                throw (UnknownHostException) e.getCause();
+            }
+            if (e.getCause() instanceof RuntimeException) {
+                throw (RuntimeException) e.getCause();
+            }
+            throw new IllegalStateException("Unknown InvocationTargetException", e.getCause());
+        } catch (IllegalAccessException | NoSuchMethodException e) {
+            Log.wtf(InetAddressCompat.class.getSimpleName(), "Error calling " + method, e);
+            throw new IllegalStateException("Error querying via " + method, e);
+        }
+    }
+}
diff --git a/packages/Connectivity/framework/src/android/net/MacAddress.java b/packages/Connectivity/framework/src/android/net/MacAddress.java
index c83c23a..26a504a 100644
--- a/packages/Connectivity/framework/src/android/net/MacAddress.java
+++ b/packages/Connectivity/framework/src/android/net/MacAddress.java
@@ -25,7 +25,6 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import com.android.internal.util.Preconditions;
 import com.android.net.module.util.MacAddressUtils;
 
 import java.lang.annotation.Retention;
@@ -34,6 +33,7 @@
 import java.net.UnknownHostException;
 import java.security.SecureRandom;
 import java.util.Arrays;
+import java.util.Objects;
 
 /**
  * Representation of a MAC address.
@@ -229,7 +229,7 @@
      * @hide
      */
     public static @NonNull byte[] byteAddrFromStringAddr(String addr) {
-        Preconditions.checkNotNull(addr);
+        Objects.requireNonNull(addr);
         String[] parts = addr.split(":");
         if (parts.length != ETHER_ADDR_LEN) {
             throw new IllegalArgumentException(addr + " was not a valid MAC address");
@@ -275,7 +275,7 @@
     // Internal conversion function equivalent to longAddrFromByteAddr(byteAddrFromStringAddr(addr))
     // that avoids the allocation of an intermediary byte[].
     private static long longAddrFromStringAddr(String addr) {
-        Preconditions.checkNotNull(addr);
+        Objects.requireNonNull(addr);
         String[] parts = addr.split(":");
         if (parts.length != ETHER_ADDR_LEN) {
             throw new IllegalArgumentException(addr + " was not a valid MAC address");
@@ -364,8 +364,8 @@
      *
      */
     public boolean matches(@NonNull MacAddress baseAddress, @NonNull MacAddress mask) {
-        Preconditions.checkNotNull(baseAddress);
-        Preconditions.checkNotNull(mask);
+        Objects.requireNonNull(baseAddress);
+        Objects.requireNonNull(mask);
         return (mAddr & mask.mAddr) == (baseAddress.mAddr & mask.mAddr);
     }
 
diff --git a/packages/Connectivity/framework/src/android/net/Network.java b/packages/Connectivity/framework/src/android/net/Network.java
index 7245db3..0741414 100644
--- a/packages/Connectivity/framework/src/android/net/Network.java
+++ b/packages/Connectivity/framework/src/android/net/Network.java
@@ -142,7 +142,7 @@
      * @throws UnknownHostException if the address lookup fails.
      */
     public InetAddress[] getAllByName(String host) throws UnknownHostException {
-        return InetAddress.getAllByNameOnNet(host, getNetIdForResolv());
+        return InetAddressCompat.getAllByNameOnNet(host, getNetIdForResolv());
     }
 
     /**
@@ -155,7 +155,7 @@
      *             if the address lookup fails.
      */
     public InetAddress getByName(String host) throws UnknownHostException {
-        return InetAddress.getByNameOnNet(host, getNetIdForResolv());
+        return InetAddressCompat.getByNameOnNet(host, getNetIdForResolv());
     }
 
     /**
diff --git a/packages/Connectivity/framework/src/android/net/NetworkAgent.java b/packages/Connectivity/framework/src/android/net/NetworkAgent.java
index a127c6f..1416bb9 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkAgent.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkAgent.java
@@ -34,8 +34,6 @@
 import android.telephony.data.EpsBearerQosSessionAttributes;
 import android.util.Log;
 
-import com.android.connectivity.aidl.INetworkAgent;
-import com.android.connectivity.aidl.INetworkAgentRegistry;
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.lang.annotation.Retention;
diff --git a/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java b/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java
index 664c265..5e50a64 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java
@@ -50,7 +50,8 @@
      * ap in the wifi settings to trigger a connection is explicit.  A 3rd party app asking to
      * connect to a particular access point is also explicit, though this may change in the future
      * as we want apps to use the multinetwork apis.
-     *
+     * TODO : this is a bad name, because it sounds like the user just tapped on the network.
+     * It's not necessarily the case ; auto-reconnection to WiFi has this true for example.
      * @hide
      */
     public boolean explicitlySelected;
diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
index 058f3c9..1466629 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
@@ -22,6 +22,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.net.ConnectivityManager.NetworkCallback;
@@ -32,10 +33,10 @@
 import android.os.Process;
 import android.text.TextUtils;
 import android.util.ArraySet;
+import android.util.Range;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
 import com.android.net.module.util.CollectionUtils;
 import com.android.net.module.util.NetworkCapabilitiesUtils;
 
@@ -153,7 +154,7 @@
             setTransportInfo(null);
         }
         mSignalStrength = nc.mSignalStrength;
-        setUids(nc.mUids); // Will make the defensive copy
+        mUids = (nc.mUids == null) ? null : new ArraySet<>(nc.mUids);
         setAdministratorUids(nc.getAdministratorUids());
         mOwnerUid = nc.mOwnerUid;
         mUnwantedNetworkCapabilities = nc.mUnwantedNetworkCapabilities;
@@ -609,10 +610,8 @@
      * Gets all the capabilities set on this {@code NetworkCapability} instance.
      *
      * @return an array of capability values for this instance.
-     * @hide
      */
-    @UnsupportedAppUsage
-    public @NetCapability int[] getCapabilities() {
+    public @NonNull @NetCapability int[] getCapabilities() {
         return NetworkCapabilitiesUtils.unpackBits(mNetworkCapabilities);
     }
 
@@ -1458,9 +1457,8 @@
      * @hide
      */
     public @NonNull NetworkCapabilities setSingleUid(int uid) {
-        final ArraySet<UidRange> identity = new ArraySet<>(1);
-        identity.add(new UidRange(uid, uid));
-        setUids(identity);
+        mUids = new ArraySet<>(1);
+        mUids.add(new UidRange(uid, uid));
         return this;
     }
 
@@ -1469,22 +1467,34 @@
      * This makes a copy of the set so that callers can't modify it after the call.
      * @hide
      */
-    public @NonNull NetworkCapabilities setUids(Set<UidRange> uids) {
-        if (null == uids) {
-            mUids = null;
-        } else {
-            mUids = new ArraySet<>(uids);
-        }
+    public @NonNull NetworkCapabilities setUids(@Nullable Set<Range<Integer>> uids) {
+        mUids = UidRange.fromIntRanges(uids);
         return this;
     }
 
     /**
      * Get the list of UIDs this network applies to.
      * This returns a copy of the set so that callers can't modify the original object.
+     *
+     * @return the list of UIDs this network applies to. If {@code null}, then the network applies
+     *         to all UIDs.
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    @SuppressLint("NullableCollection")
+    public @Nullable Set<Range<Integer>> getUids() {
+        return UidRange.toIntRanges(mUids);
+    }
+
+    /**
+     * Get the list of UIDs this network applies to.
+     * This returns a copy of the set so that callers can't modify the original object.
      * @hide
      */
-    public @Nullable Set<UidRange> getUids() {
-        return null == mUids ? null : new ArraySet<>(mUids);
+    public @Nullable Set<UidRange> getUidRanges() {
+        if (mUids == null) return null;
+
+        return new ArraySet<>(mUids);
     }
 
     /**
@@ -2099,8 +2109,9 @@
     }
 
     private static void checkValidTransportType(@Transport int transport) {
-        Preconditions.checkArgument(
-                isValidTransport(transport), "Invalid TransportType " + transport);
+        if (!isValidTransport(transport)) {
+            throw new IllegalArgumentException("Invalid TransportType " + transport);
+        }
     }
 
     private static boolean isValidCapability(@NetworkCapabilities.NetCapability int capability) {
@@ -2108,8 +2119,9 @@
     }
 
     private static void checkValidCapability(@NetworkCapabilities.NetCapability int capability) {
-        Preconditions.checkArgument(isValidCapability(capability),
-                "NetworkCapability " + capability + "out of range");
+        if (!isValidCapability(capability)) {
+            throw new IllegalArgumentException("NetworkCapability " + capability + "out of range");
+        }
     }
 
     /**
@@ -2655,6 +2667,21 @@
         }
 
         /**
+         * Set the list of UIDs this network applies to.
+         *
+         * @param uids the list of UIDs this network applies to, or {@code null} if this network
+         *             applies to all UIDs.
+         * @return this builder
+         * @hide
+         */
+        @NonNull
+        @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+        public Builder setUids(@Nullable Set<Range<Integer>> uids) {
+            mCaps.setUids(uids);
+            return this;
+        }
+
+        /**
          * Builds the instance of the capabilities.
          *
          * @return the built instance of NetworkCapabilities.
diff --git a/packages/Connectivity/framework/src/android/net/NetworkRequest.java b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
index dbe3ecc..cf131f0 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkRequest.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
@@ -36,6 +36,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.net.NetworkCapabilities.NetCapability;
@@ -45,6 +46,7 @@
 import android.os.Parcelable;
 import android.os.Process;
 import android.text.TextUtils;
+import android.util.Range;
 import android.util.proto.ProtoOutputStream;
 
 import java.util.Arrays;
@@ -277,11 +279,14 @@
          * Set the watched UIDs for this request. This will be reset and wiped out unless
          * the calling app holds the CHANGE_NETWORK_STATE permission.
          *
-         * @param uids The watched UIDs as a set of UidRanges, or null for everything.
+         * @param uids The watched UIDs as a set of {@code Range<Integer>}, or null for everything.
          * @return The builder to facilitate chaining.
          * @hide
          */
-        public Builder setUids(Set<UidRange> uids) {
+        @NonNull
+        @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+        @SuppressLint("MissingGetterMatchingBuilder")
+        public Builder setUids(@Nullable Set<Range<Integer>> uids) {
             mNetworkCapabilities.setUids(uids);
             return this;
         }
diff --git a/core/java/android/net/NetworkScore.java b/packages/Connectivity/framework/src/android/net/NetworkScore.java
similarity index 76%
rename from core/java/android/net/NetworkScore.java
rename to packages/Connectivity/framework/src/android/net/NetworkScore.java
index f478010..eadcb2d 100644
--- a/core/java/android/net/NetworkScore.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkScore.java
@@ -20,6 +20,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 /**
  * Object representing the quality of a network as perceived by the user.
  *
@@ -33,19 +35,39 @@
     // a migration.
     private final int mLegacyInt;
 
+    // Agent-managed policies
+    // TODO : add them here, starting from 1
     /** @hide */
-    NetworkScore(final int legacyInt) {
-        this.mLegacyInt = legacyInt;
+    public static final int MIN_AGENT_MANAGED_POLICY = 0;
+    /** @hide */
+    public static final int MAX_AGENT_MANAGED_POLICY = -1;
+
+    // Bitmask of all the policies applied to this score.
+    private final long mPolicies;
+
+    /** @hide */
+    NetworkScore(final int legacyInt, final long policies) {
+        mLegacyInt = legacyInt;
+        mPolicies = policies;
     }
 
     private NetworkScore(@NonNull final Parcel in) {
         mLegacyInt = in.readInt();
+        mPolicies = in.readLong();
     }
 
     public int getLegacyInt() {
         return mLegacyInt;
     }
 
+    /**
+     * @return whether this score has a particular policy.
+     */
+    @VisibleForTesting
+    public boolean hasPolicy(final int policy) {
+        return 0 != (mPolicies & (1L << policy));
+    }
+
     @Override
     public String toString() {
         return "Score(" + mLegacyInt + ")";
@@ -54,6 +76,7 @@
     @Override
     public void writeToParcel(@NonNull final Parcel dest, final int flags) {
         dest.writeInt(mLegacyInt);
+        dest.writeLong(mPolicies);
     }
 
     @Override
@@ -79,6 +102,7 @@
      * A builder for NetworkScore.
      */
     public static final class Builder {
+        private static final long POLICY_NONE = 0L;
         private static final int INVALID_LEGACY_INT = Integer.MIN_VALUE;
         private int mLegacyInt = INVALID_LEGACY_INT;
 
@@ -102,7 +126,7 @@
          */
         @NonNull
         public NetworkScore build() {
-            return new NetworkScore(mLegacyInt);
+            return new NetworkScore(mLegacyInt, POLICY_NONE);
         }
     }
 }
diff --git a/packages/Connectivity/framework/src/android/net/StaticIpConfiguration.java b/packages/Connectivity/framework/src/android/net/StaticIpConfiguration.java
index ce54597..7904f7a 100644
--- a/packages/Connectivity/framework/src/android/net/StaticIpConfiguration.java
+++ b/packages/Connectivity/framework/src/android/net/StaticIpConfiguration.java
@@ -24,7 +24,6 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import com.android.internal.util.Preconditions;
 import com.android.net.module.util.InetAddressUtils;
 
 import java.net.InetAddress;
@@ -153,7 +152,7 @@
          * @return The {@link Builder} for chaining.
          */
         public @NonNull Builder setDnsServers(@NonNull Iterable<InetAddress> dnsServers) {
-            Preconditions.checkNotNull(dnsServers);
+            Objects.requireNonNull(dnsServers);
             mDnsServers = dnsServers;
             return this;
         }
diff --git a/packages/Connectivity/framework/src/android/net/TestNetworkManager.java b/packages/Connectivity/framework/src/android/net/TestNetworkManager.java
index a174a7b..a7a6235 100644
--- a/packages/Connectivity/framework/src/android/net/TestNetworkManager.java
+++ b/packages/Connectivity/framework/src/android/net/TestNetworkManager.java
@@ -21,10 +21,9 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 
-import com.android.internal.util.Preconditions;
-
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Objects;
 
 /**
  * Class that allows creation and management of per-app, test-only networks
@@ -50,7 +49,7 @@
 
     /** @hide */
     public TestNetworkManager(@NonNull ITestNetworkManager service) {
-        mService = Preconditions.checkNotNull(service, "missing ITestNetworkManager");
+        mService = Objects.requireNonNull(service, "missing ITestNetworkManager");
     }
 
     /**
@@ -93,7 +92,7 @@
      */
     public void setupTestNetwork(
             @NonNull LinkProperties lp, boolean isMetered, @NonNull IBinder binder) {
-        Preconditions.checkNotNull(lp, "Invalid LinkProperties");
+        Objects.requireNonNull(lp, "Invalid LinkProperties");
         setupTestNetwork(lp.getInterfaceName(), lp, isMetered, new int[0], binder);
     }
 
diff --git a/packages/Connectivity/framework/src/android/net/TestNetworkSpecifier.java b/packages/Connectivity/framework/src/android/net/TestNetworkSpecifier.java
index b7470a5..117457d 100644
--- a/packages/Connectivity/framework/src/android/net/TestNetworkSpecifier.java
+++ b/packages/Connectivity/framework/src/android/net/TestNetworkSpecifier.java
@@ -23,8 +23,6 @@
 import android.os.Parcelable;
 import android.text.TextUtils;
 
-import com.android.internal.util.Preconditions;
-
 import java.util.Objects;
 
 /**
@@ -43,7 +41,9 @@
     private final String mInterfaceName;
 
     public TestNetworkSpecifier(@NonNull String interfaceName) {
-        Preconditions.checkStringNotEmpty(interfaceName);
+        if (TextUtils.isEmpty(interfaceName)) {
+            throw new IllegalArgumentException("Empty interfaceName");
+        }
         mInterfaceName = interfaceName;
     }
 
diff --git a/packages/Connectivity/framework/src/android/net/UidRange.java b/packages/Connectivity/framework/src/android/net/UidRange.java
index 26518d3..bc67c74 100644
--- a/packages/Connectivity/framework/src/android/net/UidRange.java
+++ b/packages/Connectivity/framework/src/android/net/UidRange.java
@@ -20,8 +20,11 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.UserHandle;
+import android.util.ArraySet;
+import android.util.Range;
 
 import java.util.Collection;
+import java.util.Set;
 
 /**
  * An inclusive range of UIDs.
@@ -149,4 +152,32 @@
         }
         return false;
     }
+
+    /**
+     *  Convert a set of {@code Range<Integer>} to a set of {@link UidRange}.
+     */
+    @Nullable
+    public static ArraySet<UidRange> fromIntRanges(@Nullable Set<Range<Integer>> ranges) {
+        if (null == ranges) return null;
+
+        final ArraySet<UidRange> uids = new ArraySet<>();
+        for (Range<Integer> range : ranges) {
+            uids.add(new UidRange(range.getLower(), range.getUpper()));
+        }
+        return uids;
+    }
+
+    /**
+     *  Convert a set of {@link UidRange} to a set of {@code Range<Integer>}.
+     */
+    @Nullable
+    public static ArraySet<Range<Integer>> toIntRanges(@Nullable Set<UidRange> ranges) {
+        if (null == ranges) return null;
+
+        final ArraySet<Range<Integer>> uids = new ArraySet<>();
+        for (UidRange range : ranges) {
+            uids.add(new Range<Integer>(range.start, range.stop));
+        }
+        return uids;
+    }
 }
diff --git a/packages/Connectivity/framework/src/android/net/apf/ApfCapabilities.java b/packages/Connectivity/framework/src/android/net/apf/ApfCapabilities.java
index bf5b26e..85b24713 100644
--- a/packages/Connectivity/framework/src/android/net/apf/ApfCapabilities.java
+++ b/packages/Connectivity/framework/src/android/net/apf/ApfCapabilities.java
@@ -19,12 +19,12 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.content.Context;
 import android.content.res.Resources;
+import android.net.ConnectivityResources;
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import com.android.internal.R;
-
 /**
  * APF program support capabilities. APF stands for Android Packet Filtering and it is a flexible
  * way to drop unwanted network packets to save power.
@@ -36,6 +36,8 @@
  */
 @SystemApi
 public final class ApfCapabilities implements Parcelable {
+    private static ConnectivityResources sResources;
+
     /**
      * Version of APF instruction set supported for packet filtering. 0 indicates no support for
      * packet filtering using APF programs.
@@ -65,6 +67,14 @@
         apfPacketFormat = in.readInt();
     }
 
+    @NonNull
+    private static synchronized ConnectivityResources getResources(@NonNull Context ctx) {
+        if (sResources == null)  {
+            sResources = new ConnectivityResources(ctx);
+        }
+        return sResources;
+    }
+
 
     @Override
     public int describeContents() {
@@ -121,13 +131,43 @@
      * @return Whether the APF Filter in the device should filter out IEEE 802.3 Frames.
      */
     public static boolean getApfDrop8023Frames() {
-        return Resources.getSystem().getBoolean(R.bool.config_apfDrop802_3Frames);
+        // TODO(b/183076074): remove reading resources from system resources
+        final Resources systemRes = Resources.getSystem();
+        final int id = systemRes.getIdentifier("config_apfDrop802_3Frames", "bool", "android");
+        return systemRes.getBoolean(id);
+    }
+
+    /**
+     * @return Whether the APF Filter in the device should filter out IEEE 802.3 Frames.
+     * @hide
+     */
+    public static boolean getApfDrop8023Frames(@NonNull Context context) {
+        final ConnectivityResources res = getResources(context);
+        // TODO(b/183076074): use R.bool.config_apfDrop802_3Frames directly
+        final int id = res.get().getIdentifier("config_apfDrop802_3Frames", "bool",
+                res.getResourcesContext().getPackageName());
+        return res.get().getBoolean(id);
     }
 
     /**
      * @return An array of denylisted EtherType, packets with EtherTypes within it will be dropped.
      */
     public static @NonNull int[] getApfEtherTypeBlackList() {
-        return Resources.getSystem().getIntArray(R.array.config_apfEthTypeBlackList);
+        // TODO(b/183076074): remove reading resources from system resources
+        final Resources systemRes = Resources.getSystem();
+        final int id = systemRes.getIdentifier("config_apfEthTypeBlackList", "array", "android");
+        return systemRes.getIntArray(id);
+    }
+
+    /**
+     * @return An array of denylisted EtherType, packets with EtherTypes within it will be dropped.
+     * @hide
+     */
+    public static @NonNull int[] getApfEtherTypeDenyList(@NonNull Context context) {
+        final ConnectivityResources res = getResources(context);
+        // TODO(b/183076074): use R.array.config_apfEthTypeDenyList directly
+        final int id = res.get().getIdentifier("config_apfEthTypeDenyList", "array",
+                res.getResourcesContext().getPackageName());
+        return res.get().getIntArray(id);
     }
 }
diff --git a/packages/Connectivity/framework/src/android/net/util/KeepaliveUtils.java b/packages/Connectivity/framework/src/android/net/util/KeepaliveUtils.java
index bfc4563..8d7a0b3 100644
--- a/packages/Connectivity/framework/src/android/net/util/KeepaliveUtils.java
+++ b/packages/Connectivity/framework/src/android/net/util/KeepaliveUtils.java
@@ -19,12 +19,11 @@
 import android.annotation.NonNull;
 import android.content.Context;
 import android.content.res.Resources;
+import android.net.ConnectivityResources;
 import android.net.NetworkCapabilities;
 import android.text.TextUtils;
 import android.util.AndroidRuntimeException;
 
-import com.android.internal.R;
-
 /**
  * Collection of utilities for socket keepalive offload.
  *
@@ -52,8 +51,11 @@
     public static int[] getSupportedKeepalives(@NonNull Context context) {
         String[] res = null;
         try {
-            res = context.getResources().getStringArray(
-                    R.array.config_networkSupportedKeepaliveCount);
+            final ConnectivityResources connRes = new ConnectivityResources(context);
+            // TODO: use R.id.config_networkSupportedKeepaliveCount directly
+            final int id = connRes.get().getIdentifier("config_networkSupportedKeepaliveCount",
+                    "array", connRes.getResourcesContext().getPackageName());
+            res = new ConnectivityResources(context).get().getStringArray(id);
         } catch (Resources.NotFoundException unused) {
         }
         if (res == null) throw new KeepaliveDeviceConfigurationException("invalid resource");
diff --git a/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java b/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java
index 6a49aa2..0b42a00 100644
--- a/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java
+++ b/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java
@@ -27,6 +27,7 @@
 import android.content.IntentFilter;
 import android.content.res.Resources;
 import android.database.ContentObserver;
+import android.net.ConnectivityResources;
 import android.net.Uri;
 import android.os.Handler;
 import android.provider.Settings;
@@ -35,7 +36,6 @@
 import android.telephony.TelephonyManager;
 import android.util.Log;
 
-import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.Arrays;
@@ -64,6 +64,7 @@
     private static String TAG = MultinetworkPolicyTracker.class.getSimpleName();
 
     private final Context mContext;
+    private final ConnectivityResources mResources;
     private final Handler mHandler;
     private final Runnable mAvoidBadWifiCallback;
     private final List<Uri> mSettingsUris;
@@ -107,6 +108,7 @@
 
     public MultinetworkPolicyTracker(Context ctx, Handler handler, Runnable avoidBadWifiCallback) {
         mContext = ctx;
+        mResources = new ConnectivityResources(ctx);
         mHandler = handler;
         mAvoidBadWifiCallback = avoidBadWifiCallback;
         mSettingsUris = Arrays.asList(
@@ -160,12 +162,16 @@
      * Whether the device or carrier configuration disables avoiding bad wifi by default.
      */
     public boolean configRestrictsAvoidBadWifi() {
-        return (getResourcesForActiveSubId().getInteger(R.integer.config_networkAvoidBadWifi) == 0);
+        // TODO: use R.integer.config_networkAvoidBadWifi directly
+        final int id = mResources.get().getIdentifier("config_networkAvoidBadWifi",
+                "integer", mResources.getResourcesContext().getPackageName());
+        return (getResourcesForActiveSubId().getInteger(id) == 0);
     }
 
     @NonNull
     private Resources getResourcesForActiveSubId() {
-        return SubscriptionManager.getResourcesForSubId(mContext, mActiveSubId);
+        return SubscriptionManager.getResourcesForSubId(
+                mResources.getResourcesContext(), mActiveSubId);
     }
 
     /**
@@ -205,8 +211,10 @@
      * The default (device and carrier-dependent) value for metered multipath preference.
      */
     public int configMeteredMultipathPreference() {
-        return mContext.getResources().getInteger(
-                R.integer.config_networkMeteredMultipathPreference);
+        // TODO: use R.integer.config_networkMeteredMultipathPreference directly
+        final int id = mResources.get().getIdentifier("config_networkMeteredMultipathPreference",
+                "integer", mResources.getResourcesContext().getPackageName());
+        return mResources.get().getInteger(id);
     }
 
     public void updateMeteredMultipathPreference() {
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/Android.bp b/packages/Connectivity/service/ServiceConnectivityResources/Android.bp
index f2446b7..fa4501a 100644
--- a/packages/Connectivity/service/ServiceConnectivityResources/Android.bp
+++ b/packages/Connectivity/service/ServiceConnectivityResources/Android.bp
@@ -21,7 +21,7 @@
 
 android_app {
     name: "ServiceConnectivityResources",
-    sdk_version: "system_current",
+    sdk_version: "module_current",
     resource_dirs: [
         "res",
     ],
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-hdpi/stat_notify_rssi_in_range.png b/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-hdpi/stat_notify_rssi_in_range.png
new file mode 100644
index 0000000..74977e6
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-hdpi/stat_notify_rssi_in_range.png
Binary files differ
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-mdpi/stat_notify_rssi_in_range.png b/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-mdpi/stat_notify_rssi_in_range.png
new file mode 100644
index 0000000..62e4fe9
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-mdpi/stat_notify_rssi_in_range.png
Binary files differ
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-xhdpi/stat_notify_rssi_in_range.png b/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-xhdpi/stat_notify_rssi_in_range.png
new file mode 100644
index 0000000..c0586d8
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-xhdpi/stat_notify_rssi_in_range.png
Binary files differ
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-xxhdpi/stat_notify_rssi_in_range.png b/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-xxhdpi/stat_notify_rssi_in_range.png
new file mode 100644
index 0000000..86c34ed
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-xxhdpi/stat_notify_rssi_in_range.png
Binary files differ
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/drawable/stat_notify_wifi_in_range.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/drawable/stat_notify_wifi_in_range.xml
new file mode 100644
index 0000000..a271ca5
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/drawable/stat_notify_wifi_in_range.xml
@@ -0,0 +1,27 @@
+<!--
+Copyright (C) 2014 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="26.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="26.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#4DFFFFFF"
+        android:pathData="M19.1,14l-3.4,0l0,-1.5c0,-1.8 0.8,-2.8 1.5,-3.4C18.1,8.3 19.200001,8 20.6,8c1.2,0 2.3,0.3 3.1,0.8l1.9,-2.3C25.1,6.1 20.299999,2.1 13,2.1S0.9,6.1 0.4,6.5L13,22l0,0l0,0l0,0l0,0l6.5,-8.1L19.1,14z"/>
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M19.5,17.799999c0,-0.8 0.1,-1.3 0.2,-1.6c0.2,-0.3 0.5,-0.7 1.1,-1.2c0.4,-0.4 0.7,-0.8 1,-1.1s0.4,-0.8 0.4,-1.2c0,-0.5 -0.1,-0.9 -0.4,-1.2c-0.3,-0.3 -0.7,-0.4 -1.2,-0.4c-0.4,0 -0.8,0.1 -1.1,0.3c-0.3,0.2 -0.4,0.6 -0.4,1.1l-1.9,0c0,-1 0.3,-1.7 1,-2.2c0.6,-0.5 1.5,-0.8 2.5,-0.8c1.1,0 2,0.3 2.6,0.8c0.6,0.5 0.9,1.3 0.9,2.3c0,0.7 -0.2,1.3 -0.6,1.8c-0.4,0.6 -0.9,1.1 -1.5,1.6c-0.3,0.3 -0.5,0.5 -0.6,0.7c-0.1,0.2 -0.1,0.6 -0.1,1L19.5,17.700001zM21.4,21l-1.9,0l0,-1.8l1.9,0L21.4,21z"/>
+</vector>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-af/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-af/strings.xml
new file mode 100644
index 0000000..68720d5
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-af/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Meld aan by Wi-Fi-netwerk"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Meld by netwerk aan"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> het geen internettoegang nie"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Tik vir opsies"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Selnetwerk het nie internettoegang nie"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Netwerk het nie internettoegang nie"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Daar kan nie by private DNS-bediener ingegaan word nie"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> het beperkte konnektiwiteit"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tik om in elk geval te koppel"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Het oorgeskakel na <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Toestel gebruik <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wanneer <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> geen internettoegang het nie. Heffings kan geld."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Het oorgeskakel van <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"\'n onbekende netwerktipe"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"mobiele data"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-am/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-am/strings.xml
new file mode 100644
index 0000000..78d9283
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-am/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"ወደ Wi-Fi አውታረ መረብ በመለያ ግባ"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"ወደ አውታረ መረብ በመለያ ይግቡ"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ምንም የበይነ መረብ መዳረሻ የለም"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"ለአማራጮች መታ ያድርጉ"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"የተንቀሳቃሽ ስልክ አውታረ መረብ የበይነመረብ መዳረሻ የለውም"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"አውታረ መረብ የበይነመረብ መዳረሻ የለውም"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"የግል ዲኤንኤስ አገልጋይ ሊደረስበት አይችልም"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> የተገደበ ግንኙነት አለው"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"ለማንኛውም ለማገናኘት መታ ያድርጉ"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"ወደ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ተቀይሯል"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ምንም ዓይነት የበይነመረብ ግንኙነት በማይኖረው ጊዜ መሣሪያዎች <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ን ይጠቀማሉ። ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ።"</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"ከ<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ወደ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ተቀይሯል"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"አንድ ያልታወቀ አውታረ መረብ ዓይነት"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"የተንቀሳቃሽ ስልክ ውሂብ"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"ብሉቱዝ"</item>
+    <item msgid="1616528372438698248">"ኤተርኔት"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ar/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ar/strings.xml
new file mode 100644
index 0000000..8698a7e
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ar/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"‏تسجيل الدخول إلى شبكة Wi-Fi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"تسجيل الدخول إلى الشبكة"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"لا يتوفّر في <xliff:g id="NETWORK_SSID">%1$s</xliff:g> إمكانية الاتصال بالإنترنت."</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"انقر للحصول على الخيارات."</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"شبكة الجوّال هذه غير متصلة بالإنترنت"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"الشبكة غير متصلة بالإنترنت"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"لا يمكن الوصول إلى خادم أسماء نظام نطاقات خاص"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"إمكانية اتصال <xliff:g id="NETWORK_SSID">%1$s</xliff:g> محدودة."</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"يمكنك النقر للاتصال على أي حال."</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"تم التبديل إلى <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"يستخدم الجهاز <xliff:g id="NEW_NETWORK">%1$s</xliff:g> عندما لا يتوفر اتصال بالإنترنت في شبكة <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>، ويمكن أن يتم فرض رسوم مقابل ذلك."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"تم التبديل من <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> إلى <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"نوع شبكة غير معروف"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"بيانات الجوّال"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"بلوتوث"</item>
+    <item msgid="1616528372438698248">"إيثرنت"</item>
+    <item msgid="9177085807664964627">"‏شبكة افتراضية خاصة (VPN)"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-as/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-as/strings.xml
new file mode 100644
index 0000000..10b234a
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-as/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"ৱাই-ফাই নেটৱৰ্কত ছাইন ইন কৰক"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"নেটৱৰ্কত ছাইন ইন কৰক"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>ৰ ইণ্টাৰনেটৰ এক্সেছ নাই"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"অধিক বিকল্পৰ বাবে টিপক"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"ম’বাইল নেটৱৰ্কৰ কোনো ইণ্টাৰনেটৰ এক্সেছ নাই"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"নেটৱৰ্কৰ কোনো ইণ্টাৰনেটৰ এক্সেছ নাই"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"ব্যক্তিগত DNS ছাৰ্ভাৰ এক্সেছ কৰিব নোৱাৰি"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>ৰ সকলো সেৱাৰ এক্সেছ নাই"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"যিকোনো প্ৰকাৰে সংযোগ কৰিবলৈ টিপক"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>লৈ সলনি কৰা হ’ল"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"যেতিয়া <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>ত ইণ্টাৰনেট নাথাকে, তেতিয়া ডিভাইচে <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ক ব্যৱহাৰ কৰে। মাচুল প্ৰযোজ্য হ\'ব পাৰে।"</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>ৰ পৰা <xliff:g id="NEW_NETWORK">%2$s</xliff:g> লৈ সলনি কৰা হ’ল"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"অজ্ঞাত প্ৰকাৰৰ নেটৱৰ্ক"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"ম’বাইল ডেটা"</item>
+    <item msgid="5520925862115353992">"ৱাই-ফাই"</item>
+    <item msgid="1055487873974272842">"ব্লুটুথ"</item>
+    <item msgid="1616528372438698248">"ইথাৰনেট"</item>
+    <item msgid="9177085807664964627">"ভিপিএন"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-az/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-az/strings.xml
new file mode 100644
index 0000000..d75a204
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-az/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi şəbəkəsinə daxil ol"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Şəbəkəyə daxil olun"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> üçün internet girişi əlçatan deyil"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Seçimlər üçün tıklayın"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Mobil şəbəkənin internetə girişi yoxdur"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Şəbəkənin internetə girişi yoxdur"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Özəl DNS serverinə giriş mümkün deyil"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> bağlantını məhdudlaşdırdı"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"İstənilən halda klikləyin"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> şəbəkə növünə keçirildi"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> şəbəkəsinin internetə girişi olmadıqda, cihaz <xliff:g id="NEW_NETWORK">%1$s</xliff:g> şəbəkəsini istifadə edir. Xidmət haqqı tutula bilər."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> şəbəkəsindən <xliff:g id="NEW_NETWORK">%2$s</xliff:g> şəbəkəsinə keçirildi"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"naməlum şəbəkə növü"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"mobil data"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-b+sr+Latn/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..11e4957
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Prijavljivanje na WiFi mrežu"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Prijavite se na mrežu"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nema pristup internetu"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Dodirnite za opcije"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilna mreža nema pristup internetu"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Mreža nema pristup internetu"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Pristup privatnom DNS serveru nije uspeo"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ima ograničenu vezu"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Dodirnite da biste se ipak povezali"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Prešli ste na tip mreže <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Uređaj koristi tip mreže <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kada tip mreže <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu. Možda će se naplaćivati troškovi."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Prešli ste sa tipa mreže <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na tip mreže <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"nepoznat tip mreže"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"mobilni podaci"</item>
+    <item msgid="5520925862115353992">"WiFi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Eternet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-be/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-be/strings.xml
new file mode 100644
index 0000000..6b0b1f1
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-be/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Уваход у сетку Wi-Fi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Увайдзіце ў сетку"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> не мае доступу ў інтэрнэт"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Дакраніцеся, каб убачыць параметры"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Мабільная сетка не мае доступу ў інтэрнэт"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Сетка не мае доступу ў інтэрнэт"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Не ўдалося атрымаць доступ да прыватнага DNS-сервера"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> мае абмежаваную магчымасць падключэння"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Націсніце, каб падключыцца"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Выкананы пераход да <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Прылада выкарыстоўвае сетку <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, калі ў сетцы <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> няма доступу да інтэрнэту. Можа спаганяцца плата."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Выкананы пераход з <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> да <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"невядомы тып сеткі"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"мабільная перадача даных"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-bg/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-bg/strings.xml
new file mode 100644
index 0000000..6427bd0
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-bg/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Влизане в Wi-Fi мрежа"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Вход в мрежата"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> няма достъп до интернет"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Докоснете за опции"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Мобилната мрежа няма достъп до интернет"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Мрежата няма достъп до интернет"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Не може да се осъществи достъп до частния DNS сървър"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> има ограничена свързаност"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Докоснете, за да се свържете въпреки това"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Превключи се към <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Устройството използва <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, когато <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> няма достъп до интернет. Възможно е да бъдете таксувани."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Превключи се от <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> към <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"неизвестен тип мрежа"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"мобилни данни"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"виртуална частна мрежа (VPN)"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-bn/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-bn/strings.xml
new file mode 100644
index 0000000..74d4cd6
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-bn/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"ওয়াই-ফাই নেটওয়ার্কে সাইন-ইন করুন"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"নেটওয়ার্কে সাইন-ইন করুন"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>-এর ইন্টারনেটে অ্যাক্সেস নেই"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"বিকল্পগুলির জন্য আলতো চাপুন"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"মোবাইল নেটওয়ার্কে কোনও ইন্টারনেট অ্যাক্সেস নেই"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"নেটওয়ার্কে কোনও ইন্টারনেট অ্যাক্সেস নেই"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"ব্যক্তিগত ডিএনএস সার্ভার অ্যাক্সেস করা যাবে না"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>-এর সীমিত কানেক্টিভিটি আছে"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"তবুও কানেক্ট করতে ট্যাপ করুন"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> এ পাল্টানো হয়েছে"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> এ ইন্টারনেট অ্যাক্সেস না থাকলে <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ব্যবহার করা হয়৷ ডেটা চার্জ প্রযোজ্য৷"</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> থেকে <xliff:g id="NEW_NETWORK">%2$s</xliff:g> এ পাল্টানো হয়েছে"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"এই নেটওয়ার্কের প্রকার অজানা"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"মোবাইল ডেটা"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"ব্লুটুথ"</item>
+    <item msgid="1616528372438698248">"ইথারনেট"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-bs/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-bs/strings.xml
new file mode 100644
index 0000000..19f6e1a
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-bs/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Prijavljivanje na WiFi mrežu"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Prijava na mrežu"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"Mreža <xliff:g id="NETWORK_SSID">%1$s</xliff:g> nema pristup internetu"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Dodirnite za opcije"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilna mreža nema pristup internetu"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Mreža nema pristup internetu"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Nije moguće pristupiti privatnom DNS serveru"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"Mreža <xliff:g id="NETWORK_SSID">%1$s</xliff:g> ima ograničenu povezivost"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Dodirnite da se ipak povežete"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Prebačeno na: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Kada <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu, uređaj koristi mrežu <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Moguća je naplata usluge."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Prebačeno iz mreže <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> u <xliff:g id="NEW_NETWORK">%2$s</xliff:g> mrežu"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"nepoznata vrsta mreže"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"prijenos podataka na mobilnoj mreži"</item>
+    <item msgid="5520925862115353992">"WiFi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ca/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ca/strings.xml
new file mode 100644
index 0000000..c55684d
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ca/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Inicia la sessió a la xarxa Wi-Fi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Inicia la sessió a la xarxa"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> no té accés a Internet"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Toca per veure les opcions"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"La xarxa mòbil no té accés a Internet"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"La xarxa no té accés a Internet"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"No es pot accedir al servidor DNS privat"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> té una connectivitat limitada"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Toca per connectar igualment"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Actualment en ús: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"El dispositiu utilitza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> en cas que <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tingui accés a Internet. És possible que s\'hi apliquin càrrecs."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Abans es feia servir la xarxa <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>; ara s\'utilitza <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"una tipus de xarxa desconegut"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"dades mòbils"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-cs/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-cs/strings.xml
new file mode 100644
index 0000000..fa8c411
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-cs/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Přihlásit se k síti Wi-Fi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Přihlásit se k síti"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"Síť <xliff:g id="NETWORK_SSID">%1$s</xliff:g> nemá přístup k internetu"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Klepnutím zobrazíte možnosti"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilní síť nemá přístup k internetu"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Síť nemá přístup k internetu"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Nelze získat přístup k soukromému serveru DNS"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"Síť <xliff:g id="NETWORK_SSID">%1$s</xliff:g> umožňuje jen omezené připojení"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Klepnutím se i přesto připojíte"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Přechod na síť <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Když síť <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nebude mít přístup k internetu, zařízení použije síť <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Mohou být účtovány poplatky."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Přechod ze sítě <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na síť <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"neznámý typ sítě"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"mobilní data"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-da/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-da/strings.xml
new file mode 100644
index 0000000..f7be6df
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-da/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Log ind på Wi-Fi-netværk"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Log ind på netværk"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har ingen internetforbindelse"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Tryk for at se valgmuligheder"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilnetværket har ingen internetadgang"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Netværket har ingen internetadgang"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Der er ikke adgang til den private DNS-server"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har begrænset forbindelse"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tryk for at oprette forbindelse alligevel"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Der blev skiftet til <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Enheden benytter <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, når der ikke er internetadgang via <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>. Der opkræves muligvis betaling."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Der blev skiftet fra <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> til <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"en ukendt netværkstype"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"mobildata"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-de/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-de/strings.xml
new file mode 100644
index 0000000..1e7b80c
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-de/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"In WLAN anmelden"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Im Netzwerk anmelden"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> hat keinen Internetzugriff"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Für Optionen tippen"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Mobiles Netzwerk hat keinen Internetzugriff"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Netzwerk hat keinen Internetzugriff"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Auf den privaten DNS-Server kann nicht zugegriffen werden"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"Schlechte Verbindung mit <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tippen, um die Verbindung trotzdem herzustellen"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Zu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> gewechselt"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Auf dem Gerät werden <xliff:g id="NEW_NETWORK">%1$s</xliff:g> genutzt, wenn über <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> kein Internet verfügbar ist. Eventuell fallen Gebühren an."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Von \"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>\" zu \"<xliff:g id="NEW_NETWORK">%2$s</xliff:g>\" gewechselt"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"ein unbekannter Netzwerktyp"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"Mobile Daten"</item>
+    <item msgid="5520925862115353992">"WLAN"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-el/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-el/strings.xml
new file mode 100644
index 0000000..89647fdb
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-el/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Συνδεθείτε στο δίκτυο Wi-Fi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Σύνδεση στο δίκτυο"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"Η εφαρμογή <xliff:g id="NETWORK_SSID">%1$s</xliff:g> δεν έχει πρόσβαση στο διαδίκτυο"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Πατήστε για να δείτε τις επιλογές"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Το δίκτυο κινητής τηλεφωνίας δεν έχει πρόσβαση στο διαδίκτυο."</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Το δίκτυο δεν έχει πρόσβαση στο διαδίκτυο."</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Δεν είναι δυνατή η πρόσβαση στον ιδιωτικό διακομιστή DNS."</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"Το δίκτυο <xliff:g id="NETWORK_SSID">%1$s</xliff:g> έχει περιορισμένη συνδεσιμότητα"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Πατήστε για σύνδεση ούτως ή άλλως"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Μετάβαση σε δίκτυο <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Η συσκευή χρησιμοποιεί το δίκτυο <xliff:g id="NEW_NETWORK">%1$s</xliff:g> όταν το δίκτυο <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> δεν έχει πρόσβαση στο διαδίκτυο. Μπορεί να ισχύουν χρεώσεις."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Μετάβαση από το δίκτυο <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> στο δίκτυο <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"άγνωστος τύπος δικτύου"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"δεδομένα κινητής τηλεφωνίας"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rAU/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..d29e2ec
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rAU/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Sign in to a Wi-Fi network"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Sign in to network"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has no Internet access"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Tap for options"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Mobile network has no Internet access"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Network has no Internet access"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Private DNS server cannot be accessed"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has limited connectivity"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tap to connect anyway"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"an unknown network type"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"mobile data"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rCA/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..d29e2ec
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rCA/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Sign in to a Wi-Fi network"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Sign in to network"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has no Internet access"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Tap for options"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Mobile network has no Internet access"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Network has no Internet access"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Private DNS server cannot be accessed"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has limited connectivity"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tap to connect anyway"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"an unknown network type"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"mobile data"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rGB/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..d29e2ec
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rGB/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Sign in to a Wi-Fi network"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Sign in to network"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has no Internet access"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Tap for options"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Mobile network has no Internet access"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Network has no Internet access"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Private DNS server cannot be accessed"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has limited connectivity"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tap to connect anyway"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"an unknown network type"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"mobile data"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rIN/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..d29e2ec
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rIN/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Sign in to a Wi-Fi network"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Sign in to network"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has no Internet access"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Tap for options"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Mobile network has no Internet access"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Network has no Internet access"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Private DNS server cannot be accessed"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has limited connectivity"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tap to connect anyway"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"an unknown network type"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"mobile data"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rXC/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..cd69133
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rXC/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‏‎‏‎‎‏‎‎‏‏‏‎‎‎‏‏‏‎‎‏‏‏‎‎‏‎‏‎‏‎‏‎‏‏‏‏‎‎‏‎‏‎‏‎‏‏‎‏‎‏‏‏‎‎‏‎‏‎Sign in to Wi-Fi network‎‏‎‎‏‎"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‎‎‏‏‎‎‏‎‏‎‏‎‏‏‏‎‏‎‎‎‎‏‎‎‏‏‎‎‎‎‏‎‏‏‏‏‏‎‎‏‏‎‏‏‎‎‏‎‎‏‎‏‎‏‎‎Sign in to network‎‏‎‎‏‎"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‎‏‎‏‏‏‎‏‏‎‎‏‏‎‏‎‎‏‏‎‎‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‏‎‎‏‎‎‏‏‎<xliff:g id="NETWORK_SSID">%1$s</xliff:g>‎‏‎‎‏‏‏‎ has no internet access‎‏‎‎‏‎"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‏‏‎‎‏‏‏‏‏‏‎‎‎‎‎‏‎‎‏‎‎‏‏‎‏‎‏‎‎‎‎‎‏‏‎‏‎‎‎‏‏‏‏‎‏‎‏‎‏‎‎‏‏‏‏‎‎Tap for options‎‏‎‎‏‎"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‏‏‎‏‏‎‎‎‏‏‎‏‎‏‏‎‏‏‎‎‏‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‎‎‏‏‎‏‎‎‎‎‏‎‏‎‏‎Mobile network has no internet access‎‏‎‎‏‎"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‏‏‎‏‎‎‏‏‎‏‎‏‏‎‎‏‎‎‏‎‎‎‏‎‏‎‏‏‎‎‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‎Network has no internet access‎‏‎‎‏‎"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‏‏‏‎‏‎‎‏‏‎‎‏‎‎‏‏‏‏‏‎‏‎‏‎‏‏‎‏‏‏‎‏‏‎‎‏‏‏‎‎‎‏‎‎‏‎‏‎‎‎‎‏‏‏‎Private DNS server cannot be accessed‎‏‎‎‏‎"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‏‏‏‏‏‎‏‎‎‏‎‎‎‏‏‏‏‎‎‏‎‎‎‏‏‎‎‏‎‎‎‎‎‏‏‎‏‎‏‎‎‏‎‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="NETWORK_SSID">%1$s</xliff:g>‎‏‎‎‏‏‏‎ has limited connectivity‎‏‎‎‏‎"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‎‏‎‏‏‎‏‎‏‎‎‏‏‎‎‏‎‏‏‎‏‏‎‎‎‎‎‎‎‎‏‏‏‎‎‎‎‏‏‎‎‏‎‎‏‏‎‎‏‏‎‎‎‎‎‎Tap to connect anyway‎‏‎‎‏‎"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‏‎‎‎‎‏‎‎‏‎‎‏‎‏‏‎‎‏‏‏‎‏‏‏‏‏‏‎‏‎‎‏‏‎‏‎‏‏‏‎‎‏‎‎‎‏‎‎‏‏‏‏‎‎‎‎Switched to ‎‏‎‎‏‏‎<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‏‏‎‏‏‎‎‏‏‎‏‎‎‎‏‏‎‎‎‎‎‏‏‎‎‏‎‎‏‏‏‏‏‎‎‎‏‎‎‎‏‎‏‏‎‏‎‏‏‎‎‏‎‎‏‎‎Device uses ‎‏‎‎‏‏‎<xliff:g id="NEW_NETWORK">%1$s</xliff:g>‎‏‎‎‏‏‏‎ when ‎‏‎‎‏‏‎<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>‎‏‎‎‏‏‏‎ has no internet access. Charges may apply.‎‏‎‎‏‎"</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‎‏‏‏‏‎‏‏‎‎‏‎‎‎‎‏‎‏‏‏‏‏‎‎‏‎‏‎‏‏‏‎‏‎‎‏‎‏‎‏‎‎‎‏‎‏‎‏‏‏‏‎‏‏‏‏‏‎Switched from ‎‏‎‎‏‏‎<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to ‎‏‎‎‏‏‎<xliff:g id="NEW_NETWORK">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‎‏‏‏‏‏‎‎‏‎‏‎‏‏‏‏‎‏‏‎‏‏‎‎‎‏‎‏‎‎‏‎‏‎‎‎‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎an unknown network type‎‏‎‎‏‎"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‏‎‎‏‏‎‏‏‏‎‎‎‎‎‎‎‏‎‏‎‏‏‏‏‏‎‎‏‏‏‎‎‎‏‎‏‏‎‎‏‏‏‏‎‎‏‎‎‎‏‏‏‏‎‏‎mobile data‎‏‎‎‏‎"</item>
+    <item msgid="5520925862115353992">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‎‎‏‏‏‏‎‎‏‎‎‎‏‎‎‏‏‎‏‎‎‏‎‎‎‎‎‏‎‏‎‏‎‏‎‎‏‏‏‎‎‏‎‎‏‎‏‏‎‎‎‏‎‎‎‎Wi-Fi‎‏‎‎‏‎"</item>
+    <item msgid="1055487873974272842">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‎‏‎‎‏‎‏‏‏‎‏‏‎‎‎‏‎‏‎‎‎‎‏‎‎‎‏‎‎‎‎‏‏‏‏‏‎‎‎‎‎‎‎‎‎‏‏‎‏‎‎‏‎‏‎‎Bluetooth‎‏‎‎‏‎"</item>
+    <item msgid="1616528372438698248">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‎‏‏‎‏‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‎‎‎‏‎‎‎‏‏‎‎‏‎‎‎‏‎‎‏‎‎‎‎‏‎‎‎‎Ethernet‎‏‎‎‏‎"</item>
+    <item msgid="9177085807664964627">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‏‏‎‎‎‏‏‏‎‏‏‏‎‏‎‏‏‎‏‏‏‎‏‏‏‎‎‏‎‎‏‏‎‎‎‏‎‎‏‎‎‎‎‎‏‎‎‏‏‎VPN‎‏‎‎‏‎"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-es-rUS/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..9102dc0
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-es-rUS/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Accede a una red Wi-Fi."</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Acceder a la red"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>no tiene acceso a Internet"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Presiona para ver opciones"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"La red móvil no tiene acceso a Internet"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"La red no tiene acceso a Internet"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"No se puede acceder al servidor DNS privado"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tiene conectividad limitada"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Presiona para conectarte de todas formas"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Se cambió a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"El dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cuando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tiene acceso a Internet. Es posible que se apliquen cargos."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Se cambió de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"un tipo de red desconocido"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"Datos móviles"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-es/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-es/strings.xml
new file mode 100644
index 0000000..4c15566
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-es/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Iniciar sesión en red Wi-Fi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Iniciar sesión en la red"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> no tiene acceso a Internet"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Toca para ver opciones"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"La red móvil no tiene acceso a Internet"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"La red no tiene acceso a Internet"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"No se ha podido acceder al servidor DNS privado"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tiene una conectividad limitada"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Toca para conectarte de todas formas"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Se ha cambiado a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"El dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cuando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tiene acceso a Internet. Es posible que se apliquen cargos."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Se ha cambiado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"tipo de red desconocido"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"datos móviles"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-et/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-et/strings.xml
new file mode 100644
index 0000000..398223a
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-et/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Logi sisse WiFi-võrku"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Võrku sisselogimine"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"Võrgul <xliff:g id="NETWORK_SSID">%1$s</xliff:g> puudub Interneti-ühendus"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Puudutage valikute nägemiseks"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Mobiilsidevõrgul puudub Interneti-ühendus"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Võrgul puudub Interneti-ühendus"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Privaatsele DNS-serverile ei pääse juurde"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"Võrgu <xliff:g id="NETWORK_SSID">%1$s</xliff:g> ühendus on piiratud"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Puudutage, kui soovite siiski ühenduse luua"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Lülitati võrgule <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Seade kasutab võrku <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, kui võrgul <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> puudub juurdepääs Internetile. Rakenduda võivad tasud."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Lülitati võrgult <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> võrgule <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"tundmatu võrgutüüp"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"mobiilne andmeside"</item>
+    <item msgid="5520925862115353992">"WiFi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-eu/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-eu/strings.xml
new file mode 100644
index 0000000..dd70316
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-eu/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Hasi saioa Wi-Fi sarean"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Hasi saioa sarean"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"Ezin da konektatu Internetera <xliff:g id="NETWORK_SSID">%1$s</xliff:g> sarearen bidez"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Sakatu aukerak ikusteko"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Sare mugikorra ezin da konektatu Internetera"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Sarea ezin da konektatu Internetera"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Ezin da atzitu DNS zerbitzari pribatua"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> sareak konektagarritasun murriztua du"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Sakatu hala ere konektatzeko"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> erabiltzen ari zara orain"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> Internetera konektatzeko gauza ez denean, <xliff:g id="NEW_NETWORK">%1$s</xliff:g> erabiltzen du gailuak. Agian kostuak ordaindu beharko dituzu."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> erabiltzen ari zinen, baina <xliff:g id="NEW_NETWORK">%2$s</xliff:g> erabiltzen ari zara orain"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"sare mota ezezaguna"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"datu-konexioa"</item>
+    <item msgid="5520925862115353992">"Wifia"</item>
+    <item msgid="1055487873974272842">"Bluetooth-a"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-fa/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-fa/strings.xml
new file mode 100644
index 0000000..46a946c
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-fa/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"‏ورود به شبکه Wi-Fi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"ورود به سیستم شبکه"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> به اینترنت دسترسی ندارد"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"برای گزینه‌ها ضربه بزنید"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"شبکه تلفن همراه به اینترنت دسترسی ندارد"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"شبکه به اینترنت دسترسی ندارد"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"‏سرور DNS خصوصی قابل دسترسی نیست"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> اتصال محدودی دارد"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"به‌هرصورت، برای اتصال ضربه بزنید"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"به <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> تغییر کرد"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"وقتی <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> به اینترنت دسترسی نداشته باشد، دستگاه از <xliff:g id="NEW_NETWORK">%1$s</xliff:g> استفاده می‌کند. ممکن است هزینه‌هایی اعمال شود."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"از <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> به <xliff:g id="NEW_NETWORK">%2$s</xliff:g> تغییر کرد"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"نوع شبکه نامشخص"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"داده تلفن همراه"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"بلوتوث"</item>
+    <item msgid="1616528372438698248">"اترنت"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-fi/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-fi/strings.xml
new file mode 100644
index 0000000..dd94441
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-fi/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Kirjaudu Wi-Fi-verkkoon"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Kirjaudu verkkoon"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ei ole yhteydessä internetiin"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Näytä vaihtoehdot napauttamalla."</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Mobiiliverkko ei ole yhteydessä internetiin"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Verkko ei ole yhteydessä internetiin"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Ei pääsyä yksityiselle DNS-palvelimelle"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> toimii rajoitetulla yhteydellä"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Yhdistä napauttamalla"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> otettiin käyttöön"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> otetaan käyttöön, kun <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ei voi muodostaa yhteyttä internetiin. Veloitukset ovat mahdollisia."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> poistettiin käytöstä ja <xliff:g id="NEW_NETWORK">%2$s</xliff:g> otettiin käyttöön."</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"tuntematon verkon tyyppi"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"mobiilidata"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-fr-rCA/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..02ef50b
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-fr-rCA/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Connectez-vous au réseau Wi-Fi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Connectez-vous au réseau"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"Le réseau <xliff:g id="NETWORK_SSID">%1$s</xliff:g> n\'offre aucun accès à Internet"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Touchez pour afficher les options"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Le réseau cellulaire n\'offre aucun accès à Internet"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Le réseau n\'offre aucun accès à Internet"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Impossible d\'accéder au serveur DNS privé"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"Le réseau <xliff:g id="NETWORK_SSID">%1$s</xliff:g> offre une connectivité limitée"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Touchez pour vous connecter quand même"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Passé au réseau <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"L\'appareil utilise <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quand <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> n\'a pas d\'accès à Internet. Des frais peuvent s\'appliquer."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Passé du réseau <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> au <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"un type de réseau inconnu"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"données cellulaires"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"RPV"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-fr/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-fr/strings.xml
new file mode 100644
index 0000000..08c9d81
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-fr/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Connectez-vous au réseau Wi-Fi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Se connecter au réseau"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"Aucune connexion à Internet pour <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Appuyez ici pour afficher des options."</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Le réseau mobile ne dispose d\'aucun accès à Internet"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Le réseau ne dispose d\'aucun accès à Internet"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Impossible d\'accéder au serveur DNS privé"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"La connectivité de <xliff:g id="NETWORK_SSID">%1$s</xliff:g> est limitée"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Appuyer pour se connecter quand même"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Nouveau réseau : <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"L\'appareil utilise <xliff:g id="NEW_NETWORK">%1$s</xliff:g> lorsque <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> n\'a pas de connexion Internet. Des frais peuvent s\'appliquer."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Ancien réseau : <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>. Nouveau réseau : <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"type de réseau inconnu"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"données mobiles"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-gl/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-gl/strings.xml
new file mode 100644
index 0000000..9f98055
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-gl/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Inicia sesión na rede wifi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Inicia sesión na rede"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> non ten acceso a Internet"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Toca para ver opcións."</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"A rede de telefonía móbil non ten acceso a Internet"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"A rede non ten acceso a Internet"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Non se puido acceder ao servidor DNS privado"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"A conectividade de <xliff:g id="NETWORK_SSID">%1$s</xliff:g> é limitada"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Toca para conectarte de todas formas"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Cambiouse a: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"O dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> non ten acceso a Internet. Pódense aplicar cargos."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Cambiouse de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"un tipo de rede descoñecido"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"datos móbiles"</item>
+    <item msgid="5520925862115353992">"wifi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-gu/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-gu/strings.xml
new file mode 100644
index 0000000..4ae5a2c
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-gu/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"વાઇ-ફાઇ નેટવર્ક પર સાઇન ઇન કરો"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"નેટવર્ક પર સાઇન ઇન કરો"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ઇન્ટરનેટ ઍક્સેસ ધરાવતું નથી"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"વિકલ્પો માટે ટૅપ કરો"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"મોબાઇલ નેટવર્ક કોઈ ઇન્ટરનેટ ઍક્સેસ ધરાવતું નથી"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"નેટવર્ક કોઈ ઇન્ટરનેટ ઍક્સેસ ધરાવતું નથી"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"ખાનગી DNS સર્વર ઍક્સેસ કરી શકાતા નથી"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> મર્યાદિત કનેક્ટિવિટી ધરાવે છે"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"છતાં કનેક્ટ કરવા માટે ટૅપ કરો"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> પર સ્વિચ કર્યું"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"જ્યારે <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> પાસે કોઈ ઇન્ટરનેટ ઍક્સેસ ન હોય ત્યારે ઉપકરણ <xliff:g id="NEW_NETWORK">%1$s</xliff:g>નો ઉપયોગ કરે છે. શુલ્ક લાગુ થઈ શકે છે."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> પરથી <xliff:g id="NEW_NETWORK">%2$s</xliff:g> પર સ્વિચ કર્યું"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"અજાણ્યો નેટવર્ક પ્રકાર"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"મોબાઇલ ડેટા"</item>
+    <item msgid="5520925862115353992">"વાઇ-ફાઇ"</item>
+    <item msgid="1055487873974272842">"બ્લૂટૂથ"</item>
+    <item msgid="1616528372438698248">"ઇથરનેટ"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-hi/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-hi/strings.xml
new file mode 100644
index 0000000..eff1b60
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-hi/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"वाई-फ़ाई  नेटवर्क में साइन इन करें"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"नेटवर्क में साइन इन करें"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> का इंटरनेट नहीं चल रहा है"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"विकल्पों के लिए टैप करें"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"मोबाइल नेटवर्क पर इंटरनेट ऐक्सेस नहीं है"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"इस नेटवर्क पर इंटरनेट ऐक्सेस नहीं है"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"निजी डीएनएस सर्वर को ऐक्सेस नहीं किया जा सकता"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> की कनेक्टिविटी सीमित है"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"फिर भी कनेक्ट करने के लिए टैप करें"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> पर ले जाया गया"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> में इंटरनेट की सुविधा नहीं होने पर डिवाइस <xliff:g id="NEW_NETWORK">%1$s</xliff:g> का इस्तेमाल करता है. इसके लिए शुल्क लिया जा सकता है."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> से <xliff:g id="NEW_NETWORK">%2$s</xliff:g> पर ले जाया गया"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"अज्ञात नेटवर्क प्रकार"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"मोबाइल डेटा"</item>
+    <item msgid="5520925862115353992">"वाई-फ़ाई"</item>
+    <item msgid="1055487873974272842">"ब्लूटूथ"</item>
+    <item msgid="1616528372438698248">"ईथरनेट"</item>
+    <item msgid="9177085807664964627">"वीपीएन"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-hr/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-hr/strings.xml
new file mode 100644
index 0000000..52bfb93
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-hr/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Prijava na Wi-Fi mrežu"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Prijava na mrežu"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nema pristup internetu"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Dodirnite za opcije"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilna mreža nema pristup internetu"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Mreža nema pristup internetu"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Nije moguće pristupiti privatnom DNS poslužitelju"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ima ograničenu povezivost"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Dodirnite da biste se ipak povezali"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Prelazak na drugu mrežu: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Kada <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu, na uređaju se upotrebljava <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Moguća je naplata naknade."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Mreža je promijenjena: <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> &gt; <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"nepoznata vrsta mreže"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"mobilni podaci"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-hu/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-hu/strings.xml
new file mode 100644
index 0000000..2ff59b5
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-hu/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Bejelentkezés Wi-Fi hálózatba"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Bejelentkezés a hálózatba"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"A(z) <xliff:g id="NETWORK_SSID">%1$s</xliff:g> hálózaton nincs internet-hozzáférés"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Koppintson a beállítások megjelenítéséhez"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"A mobilhálózaton nincs internet-hozzáférés"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"A hálózaton nincs internet-hozzáférés"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"A privát DNS-kiszolgálóhoz nem lehet hozzáférni"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"A(z) <xliff:g id="NETWORK_SSID">%1$s</xliff:g> hálózat korlátozott kapcsolatot biztosít"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Koppintson, ha mindenképpen csatlakozni szeretne"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Átváltva erre: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> használata, ha nincs internet-hozzáférés <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>-kapcsolaton keresztül. A szolgáltató díjat számíthat fel."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Átváltva <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>-hálózatról erre: <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"ismeretlen hálózati típus"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"mobiladatok"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-hy/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-hy/strings.xml
new file mode 100644
index 0000000..b35d31c
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-hy/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Մուտք գործեք Wi-Fi ցանց"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Մուտք գործեք ցանց"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ցանցը չունի մուտք ինտերնետին"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Հպեք՝ ընտրանքները տեսնելու համար"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Բջջային ցանցը չի ապահովում ինտերնետ կապ"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Ցանցը միացված չէ ինտերնետին"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Մասնավոր DNS սերվերն անհասանելի է"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ցանցի կապը սահմանափակ է"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Հպեք՝ միանալու համար"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Անցել է <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ցանցի"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Երբ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ցանցում ինտերնետ կապ չի լինում, սարքն անցնում է <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ցանցի: Նման դեպքում կարող են վճարներ գանձվել:"</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ցանցից անցել է <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ցանցի"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"ցանցի անհայտ տեսակ"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"բջջային ինտերնետ"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-in/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-in/strings.xml
new file mode 100644
index 0000000..27d7d89
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-in/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Login ke jaringan Wi-Fi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Login ke jaringan"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tidak memiliki akses internet"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Ketuk untuk melihat opsi"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Jaringan seluler tidak memiliki akses internet"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Jaringan tidak memiliki akses internet"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Server DNS pribadi tidak dapat diakses"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> memiliki konektivitas terbatas"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Ketuk untuk tetap menyambungkan"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Dialihkan ke <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Perangkat menggunakan <xliff:g id="NEW_NETWORK">%1$s</xliff:g> jika <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tidak memiliki akses internet. Tarif mungkin berlaku."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Dialihkan dari <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ke <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"jenis jaringan yang tidak dikenal"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"data seluler"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-is/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-is/strings.xml
new file mode 100644
index 0000000..97f42dc
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-is/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Skrá inn á Wi-Fi net"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Skrá inn á net"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> er ekki með internetaðgang"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Ýttu til að sjá valkosti"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Farsímakerfið er ekki tengt við internetið"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Netkerfið er ekki tengt við internetið"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Ekki næst í DNS-einkaþjón"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"Tengigeta <xliff:g id="NETWORK_SSID">%1$s</xliff:g> er takmörkuð"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Ýttu til að tengjast samt"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Skipt yfir á <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Tækið notar <xliff:g id="NEW_NETWORK">%1$s</xliff:g> þegar <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> er ekki með internetaðgang. Gjöld kunna að eiga við."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Skipt úr <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> yfir í <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"óþekkt tegund netkerfis"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"farsímagögn"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-it/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-it/strings.xml
new file mode 100644
index 0000000..7836101
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-it/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Accedi a rete Wi-Fi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Accedi alla rete"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> non ha accesso a Internet"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Tocca per le opzioni"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"La rete mobile non ha accesso a Internet"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"La rete non ha accesso a Internet"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Non è possibile accedere al server DNS privato"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ha una connettività limitata"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tocca per connettere comunque"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Passato a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Il dispositivo utilizza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> non ha accesso a Internet. Potrebbero essere applicati costi."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Passato da <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"tipo di rete sconosciuto"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"dati mobili"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-iw/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-iw/strings.xml
new file mode 100644
index 0000000..f322b99
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-iw/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"‏היכנס לרשת Wi-Fi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"היכנס לרשת"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"ל-<xliff:g id="NETWORK_SSID">%1$s</xliff:g> אין גישה לאינטרנט"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"הקש לקבלת אפשרויות"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"לרשת הסלולרית אין גישה לאינטרנט"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"לרשת אין גישה לאינטרנט"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"‏לא ניתן לגשת לשרת DNS הפרטי"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"הקישוריות של <xliff:g id="NETWORK_SSID">%1$s</xliff:g> מוגבלת"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"כדי להתחבר למרות זאת יש להקיש"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"מעבר אל <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"המכשיר משתמש ברשת <xliff:g id="NEW_NETWORK">%1$s</xliff:g> כשלרשת <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> אין גישה לאינטרנט. עשויים לחול חיובים."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"עבר מרשת <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> לרשת <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"סוג רשת לא מזוהה"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"חבילת גלישה"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ja/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ja/strings.xml
new file mode 100644
index 0000000..1aa3216
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ja/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fiネットワークにログイン"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"ネットワークにログインしてください"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> はインターネットにアクセスできません"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"タップしてその他のオプションを表示"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"モバイル ネットワークがインターネットに接続されていません"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"ネットワークがインターネットに接続されていません"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"プライベート DNS サーバーにアクセスできません"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> の接続が制限されています"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"接続するにはタップしてください"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"「<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>」に切り替えました"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"デバイスで「<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>」によるインターネット接続ができない場合に「<xliff:g id="NEW_NETWORK">%1$s</xliff:g>」を使用します。通信料が発生することがあります。"</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"「<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>」から「<xliff:g id="NEW_NETWORK">%2$s</xliff:g>」に切り替えました"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"不明なネットワーク タイプ"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"モバイルデータ"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"イーサネット"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ka/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ka/strings.xml
new file mode 100644
index 0000000..61d21b5
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ka/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi ქსელთან დაკავშირება"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"ქსელში შესვლა"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>-ს არ აქვს ინტერნეტზე წვდომა"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"შეეხეთ ვარიანტების სანახავად"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"მობილურ ქსელს არ აქვს ინტერნეტზე წვდომა"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"ქსელს არ აქვს ინტერნეტზე წვდომა"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"პირად DNS სერვერზე წვდომა შეუძლებელია"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>-ის კავშირები შეზღუდულია"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"შეეხეთ, თუ მაინც გსურთ დაკავშირება"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"ახლა გამოიყენება <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"თუ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ინტერნეტთან კავშირს დაკარგავს, მოწყობილობის მიერ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> იქნება გამოყენებული, რამაც შეიძლება დამატებითი ხარჯები გამოიწვიოს."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"ახლა გამოიყენება <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> (გამოიყენებოდა <xliff:g id="NEW_NETWORK">%2$s</xliff:g>)"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"უცნობი ტიპის ქსელი"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"მობილური ინტერნეტი"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-kk/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-kk/strings.xml
new file mode 100644
index 0000000..969aaef
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-kk/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi желісіне кіру"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Желіге кіру"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> желісінің интернетті пайдалану мүмкіндігі шектеулі."</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Опциялар үшін түртіңіз"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Мобильдік желі интернетке қосылмаған."</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Желі интернетке қосылмаған."</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Жеке DNS серверіне кіру мүмкін емес."</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> желісінің қосылу мүмкіндігі шектеулі."</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Бәрібір жалғау үшін түртіңіз."</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> желісіне ауысты"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Құрылғы <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> желісінде интернетпен байланыс жоғалған жағдайда <xliff:g id="NEW_NETWORK">%1$s</xliff:g> желісін пайдаланады. Деректер ақысы алынуы мүмкін."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> желісінен <xliff:g id="NEW_NETWORK">%2$s</xliff:g> желісіне ауысты"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"желі түрі белгісіз"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"мобильдік деректер"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-km/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-km/strings.xml
new file mode 100644
index 0000000..da3c337
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-km/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"ចូល​បណ្ដាញ​វ៉ាយហ្វាយ"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"ចូលទៅបណ្តាញ"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> មិនមាន​ការតភ្ជាប់អ៊ីនធឺណិត​ទេ"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"ប៉ះសម្រាប់ជម្រើស"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"បណ្ដាញ​ទូរសព្ទ​ចល័ត​មិនមានការតភ្ជាប់​អ៊ីនធឺណិតទេ"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"បណ្ដាញ​មិនមាន​ការតភ្ជាប់​អ៊ីនធឺណិតទេ"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"មិនអាច​ចូលប្រើ​ម៉ាស៊ីនមេ DNS ឯកជន​បានទេ"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> មានការតភ្ជាប់​មានកម្រិត"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"មិន​អី​ទេ ចុច​​ភ្ជាប់​ចុះ"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"បានប្តូរទៅ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"ឧបករណ៍​ប្រើ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> នៅ​ពេល​ដែល <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> មិនមាន​ការ​តភ្ជាប់​អ៊ីនធឺណិត។ អាច​គិតថ្លៃ​លើការ​ប្រើប្រាស់​ទិន្នន័យ។"</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"បានប្តូរពី <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ទៅ <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"ប្រភេទបណ្តាញមិនស្គាល់"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"ទិន្នន័យ​ទូរសព្ទចល័ត"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"ប៊្លូធូស"</item>
+    <item msgid="1616528372438698248">"អ៊ីសឺរណិត"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-kn/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-kn/strings.xml
new file mode 100644
index 0000000..3b5e047
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-kn/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"ವೈ-ಫೈ ನೆಟ್‍ವರ್ಕ್‌ಗೆ ಸೈನ್ ಇನ್ ಮಾಡಿ"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"ನೆಟ್‌ವರ್ಕ್‌ಗೆ ಸೈನ್ ಇನ್ ಮಾಡಿ"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವನ್ನು ಹೊಂದಿಲ್ಲ"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"ಆಯ್ಕೆಗಳಿಗೆ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"ಮೊಬೈಲ್ ನೆಟ್‌ವರ್ಕ್‌ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶವನ್ನು ಹೊಂದಿಲ್ಲ"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"ನೆಟ್‌ವರ್ಕ್‌ ಇಂಟರ್ನೆಟ್‌ ಪ್ರವೇಶವನ್ನು ಹೊಂದಿಲ್ಲ"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"ಖಾಸಗಿ DNS ಸರ್ವರ್ ಅನ್ನು ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ಸೀಮಿತ ಸಂಪರ್ಕ ಕಲ್ಪಿಸುವಿಕೆಯನ್ನು ಹೊಂದಿದೆ"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"ಹೇಗಾದರೂ ಸಂಪರ್ಕಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ಗೆ ಬದಲಾಯಿಸಲಾಗಿದೆ"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶ ಹೊಂದಿಲ್ಲದಿರುವಾಗ, ಸಾಧನವು <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ಬಳಸುತ್ತದೆ. ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ರಿಂದ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ಗೆ ಬದಲಾಯಿಸಲಾಗಿದೆ"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"ಅಪರಿಚಿತ ನೆಟ್‌ವರ್ಕ್ ಪ್ರಕಾರ"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"ಮೊಬೈಲ್ ಡೇಟಾ"</item>
+    <item msgid="5520925862115353992">"ವೈ-ಫೈ"</item>
+    <item msgid="1055487873974272842">"ಬ್ಲೂಟೂತ್‌"</item>
+    <item msgid="1616528372438698248">"ಇಥರ್ನೆಟ್"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ko/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ko/strings.xml
new file mode 100644
index 0000000..874bd75
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ko/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi 네트워크에 로그인"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"네트워크에 로그인"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>이(가) 인터넷에 액세스할 수 없습니다."</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"탭하여 옵션 보기"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"모바일 네트워크에 인터넷이 연결되어 있지 않습니다."</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"네트워크에 인터넷이 연결되어 있지 않습니다."</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"비공개 DNS 서버에 액세스할 수 없습니다."</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>에서 연결을 제한했습니다."</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"계속 연결하려면 탭하세요."</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>(으)로 전환"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>(으)로 인터넷에 연결할 수 없는 경우 기기에서 <xliff:g id="NEW_NETWORK">%1$s</xliff:g>이(가) 사용됩니다. 요금이 부과될 수 있습니다."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>에서 <xliff:g id="NEW_NETWORK">%2$s</xliff:g>(으)로 전환"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"알 수 없는 네트워크 유형"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"모바일 데이터"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"블루투스"</item>
+    <item msgid="1616528372438698248">"이더넷"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ky/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ky/strings.xml
new file mode 100644
index 0000000..1ace4dc
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ky/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi түйүнүнө кирүү"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Тармакка кирүү"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> Интернетке туташуусу жок"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Параметрлерди ачуу үчүн таптап коюңуз"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Мобилдик Интернет жок"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Тармактын Интернет жок"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Жеке DNS сервери жеткиликсиз"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> байланышы чектелген"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Баары бир туташуу үчүн таптаңыз"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> тармагына которуштурулду"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> тармагы Интернетке туташпай турганда, түзмөгүңүз <xliff:g id="NEW_NETWORK">%1$s</xliff:g> тармагын колдонот. Акы алынышы мүмкүн."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> дегенден <xliff:g id="NEW_NETWORK">%2$s</xliff:g> тармагына которуштурулду"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"белгисиз тармак түрү"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"мобилдик трафик"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-lo/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-lo/strings.xml
new file mode 100644
index 0000000..3db497e
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-lo/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"ເຂົ້າສູ່ລະບົບເຄືອຂ່າຍ Wi-Fi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"ລົງຊື່ເຂົ້າເຄືອຂ່າຍ"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"ແຕະເພື່ອເບິ່ງຕົວເລືອກ"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"ເຄືອຂ່າຍມືຖືບໍ່ສາມາດເຂົ້າເຖິງອິນເຕີເນັດໄດ້"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"ເຄືອຂ່າຍບໍ່ສາມາດເຂົ້າເຖິງອິນເຕີເນັດໄດ້"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"ບໍ່ສາມາດເຂົ້າເຖິງເຊີບເວີ DNS ສ່ວນຕົວໄດ້"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ມີການເຊື່ອມຕໍ່ທີ່ຈຳກັດ"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"ແຕະເພື່ອຢືນຢັນການເຊື່ອມຕໍ່"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"ສະຫຼັບໄປໃຊ້ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ແລ້ວ"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"ອຸປະກອນຈະໃຊ້ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ເມື່ອ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ. ອາດມີການຮຽກເກັບຄ່າບໍລິການ."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"ສະຫຼັບຈາກ <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ໄປໃຊ້ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ແລ້ວ"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"ບໍ່ຮູ້ຈັກປະເພດເຄືອຂ່າຍ"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"ອິນເຕີເນັດມືຖື"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"ອີເທີເນັດ"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-lt/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-lt/strings.xml
new file mode 100644
index 0000000..c639c1f
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-lt/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Prisijungti prie „Wi-Fi“ tinklo"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Prisijungti prie tinklo"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"„<xliff:g id="NETWORK_SSID">%1$s</xliff:g>“ negali pasiekti interneto"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Palieskite, kad būtų rodomos parinktys."</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Mobiliojo ryšio tinkle nėra prieigos prie interneto"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Tinkle nėra prieigos prie interneto"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Privataus DNS serverio negalima pasiekti"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"„<xliff:g id="NETWORK_SSID">%1$s</xliff:g>“ ryšys apribotas"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Palieskite, jei vis tiek norite prisijungti"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Perjungta į tinklą <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Įrenginyje naudojamas kitas tinklas (<xliff:g id="NEW_NETWORK">%1$s</xliff:g>), kai dabartiniame tinkle (<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>) nėra interneto ryšio. Gali būti taikomi mokesčiai."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Perjungta iš tinklo <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> į tinklą <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"nežinomas tinklo tipas"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"mobiliojo ryšio duomenys"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Eternetas"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-lv/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-lv/strings.xml
new file mode 100644
index 0000000..5774603
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-lv/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Pierakstieties Wi-Fi tīklā"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Pierakstīšanās tīklā"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"Tīklā <xliff:g id="NETWORK_SSID">%1$s</xliff:g> nav piekļuves internetam"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Pieskarieties, lai skatītu iespējas."</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilajā tīklā nav piekļuves internetam."</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Tīklā nav piekļuves internetam."</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Nevar piekļūt privātam DNS serverim."</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"Tīklā <xliff:g id="NETWORK_SSID">%1$s</xliff:g> ir ierobežota savienojamība"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Lai tik un tā izveidotu savienojumu, pieskarieties"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Pārslēdzās uz tīklu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Kad vienā tīklā (<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>) nav piekļuves internetam, ierīcē tiek izmantots cits tīkls (<xliff:g id="NEW_NETWORK">%1$s</xliff:g>). Var tikt piemērota maksa."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Pārslēdzās no tīkla <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> uz tīklu <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"nezināms tīkla veids"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"mobilie dati"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc204-mnc04/config.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc204-mnc04/config.xml
new file mode 100644
index 0000000..7e7025f
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc204-mnc04/config.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.
+  -->
+
+<!-- Configuration values for ConnectivityService
+     DO NOT EDIT THIS FILE for specific device configuration; instead, use a Runtime Resources
+     Overlay package following the overlayable.xml configuration in the same directory:
+     https://source.android.com/devices/architecture/rros -->
+<resources>
+    <!-- Whether the device should automatically switch away from Wi-Fi networks that lose
+         Internet access. Actual device behaviour is controlled by
+         Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. -->
+    <integer translatable="false" name="config_networkAvoidBadWifi">0</integer>
+</resources>
\ No newline at end of file
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc310-mnc004/config.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc310-mnc004/config.xml
new file mode 100644
index 0000000..7e7025f
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc310-mnc004/config.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.
+  -->
+
+<!-- Configuration values for ConnectivityService
+     DO NOT EDIT THIS FILE for specific device configuration; instead, use a Runtime Resources
+     Overlay package following the overlayable.xml configuration in the same directory:
+     https://source.android.com/devices/architecture/rros -->
+<resources>
+    <!-- Whether the device should automatically switch away from Wi-Fi networks that lose
+         Internet access. Actual device behaviour is controlled by
+         Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. -->
+    <integer translatable="false" name="config_networkAvoidBadWifi">0</integer>
+</resources>
\ No newline at end of file
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc311-mnc480/config.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc311-mnc480/config.xml
new file mode 100644
index 0000000..7e7025f
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc311-mnc480/config.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.
+  -->
+
+<!-- Configuration values for ConnectivityService
+     DO NOT EDIT THIS FILE for specific device configuration; instead, use a Runtime Resources
+     Overlay package following the overlayable.xml configuration in the same directory:
+     https://source.android.com/devices/architecture/rros -->
+<resources>
+    <!-- Whether the device should automatically switch away from Wi-Fi networks that lose
+         Internet access. Actual device behaviour is controlled by
+         Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. -->
+    <integer translatable="false" name="config_networkAvoidBadWifi">0</integer>
+</resources>
\ No newline at end of file
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-mk/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mk/strings.xml
new file mode 100644
index 0000000..053c7cf
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mk/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Најавете се на мрежа на Wi-Fi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Најавете се на мрежа"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> нема интернет-пристап"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Допрете за опции"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Мобилната мрежа нема интернет-пристап"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Мрежата нема интернет-пристап"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Не може да се пристапи до приватниот DNS-сервер"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> има ограничена поврзливост"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Допрете за да се поврзете и покрај тоа"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Префрлено на <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Уредот користи <xliff:g id="NEW_NETWORK">%1$s</xliff:g> кога <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> нема пристап до интернет. Може да се наплатат трошоци."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Префрлено од <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"непознат тип мрежа"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"мобилен интернет"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Етернет"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ml/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ml/strings.xml
new file mode 100644
index 0000000..3e80cf1
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ml/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"വൈഫൈ നെറ്റ്‌വർക്കിലേക്ക് സൈൻ ഇൻ ചെയ്യുക"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"നെറ്റ്‌വർക്കിലേക്ക് സൈൻ ഇൻ ചെയ്യുക"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> എന്നതിന് ഇന്റർനെറ്റ് ആക്‌സസ് ഇല്ല"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"ഓപ്ഷനുകൾക്ക് ടാപ്പുചെയ്യുക"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"മൊബെെൽ നെറ്റ്‌വർക്കിന് ഇന്റർനെറ്റ് ആക്‌സസ് ഇല്ല"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"നെറ്റ്‌വർക്കിന് ഇന്റർനെറ്റ് ആക്‌സസ് ഇല്ല"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"സ്വകാര്യ DNS സെർവർ ആക്‌സസ് ചെയ്യാനാവില്ല"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> എന്നതിന് പരിമിതമായ കണക്റ്റിവിറ്റി ഉണ്ട്"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"ഏതുവിധേനയും കണക്‌റ്റ് ചെയ്യാൻ ടാപ്പ് ചെയ്യുക"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> എന്നതിലേക്ക് മാറി"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>-ന് ഇന്റർനെറ്റ് ആക്‌സസ് ഇല്ലാത്തപ്പോൾ ഉപകരണം <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ഉപയോഗിക്കുന്നു. നിരക്കുകൾ ബാധകമായേക്കാം."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> നെറ്റ്‌വർക്കിൽ നിന്ന് <xliff:g id="NEW_NETWORK">%2$s</xliff:g> നെറ്റ്‌വർക്കിലേക്ക് മാറി"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"തിരിച്ചറിയാനാകാത്ത ഒരു നെറ്റ്‌വർക്ക് തരം"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"മൊബൈൽ ഡാറ്റ"</item>
+    <item msgid="5520925862115353992">"വൈഫൈ"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"ഇതര്‍നെറ്റ്"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-mn/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mn/strings.xml
new file mode 100644
index 0000000..214fc0c
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mn/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi сүлжээнд нэвтэрнэ үү"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Сүлжээнд нэвтэрнэ үү"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>-д интернэтийн хандалт алга"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Сонголт хийхийн тулд товшино уу"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Мобайл сүлжээнд интернэт хандалт байхгүй байна"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Сүлжээнд интернэт хандалт байхгүй байна"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Хувийн DNS серверт хандах боломжгүй байна"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> зарим үйлчилгээнд хандах боломжгүй байна"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Ямар ч тохиолдолд холбогдохын тулд товших"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> руу шилжүүлсэн"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> интернет холболтгүй үед төхөөрөмж <xliff:g id="NEW_NETWORK">%1$s</xliff:g>-г ашигладаг. Төлбөр гарч болзошгүй."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>-с <xliff:g id="NEW_NETWORK">%2$s</xliff:g> руу шилжүүлсэн"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"сүлжээний тодорхойгүй төрөл"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"мобайл дата"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Этернэт"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-mr/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mr/strings.xml
new file mode 100644
index 0000000..c4b1998
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mr/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"वाय-फाय नेटवर्कमध्‍ये साइन इन करा"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"नेटवर्कवर साइन इन करा"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ला इंटरनेट अ‍ॅक्सेस नाही"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"पर्यायांसाठी टॅप करा"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"मोबाइल नेटवर्कला इंटरनेट ॲक्सेस नाही"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"नेटवर्कला इंटरनेट ॲक्सेस नाही"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"खाजगी DNS सर्व्हर ॲक्सेस करू शकत नाही"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ला मर्यादित कनेक्टिव्हिटी आहे"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"तरीही कनेक्ट करण्यासाठी टॅप करा"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> वर स्विच केले"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> कडे इंटरनेटचा अ‍ॅक्सेस नसताना डिव्हाइस <xliff:g id="NEW_NETWORK">%1$s</xliff:g> वापरते. शुल्क लागू शकते."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> वरून <xliff:g id="NEW_NETWORK">%2$s</xliff:g> वर स्विच केले"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"अज्ञात नेटवर्क प्रकार"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"मोबाइल डेटा"</item>
+    <item msgid="5520925862115353992">"वाय-फाय"</item>
+    <item msgid="1055487873974272842">"ब्लूटूथ"</item>
+    <item msgid="1616528372438698248">"इथरनेट"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ms/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ms/strings.xml
new file mode 100644
index 0000000..529d0bd
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ms/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Log masuk ke rangkaian Wi-Fi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Log masuk ke rangkaian"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tiada akses Internet"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Ketik untuk mendapatkan pilihan"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Rangkaian mudah alih tiada akses Internet"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Rangkaian tiada akses Internet"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Pelayan DNS peribadi tidak boleh diakses"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> mempunyai kesambungan terhad"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Ketik untuk menyambung juga"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Beralih kepada <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Peranti menggunakan <xliff:g id="NEW_NETWORK">%1$s</xliff:g> apabila <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tiada akses Internet. Bayaran mungkin dikenakan."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Beralih daripada <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> kepada <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"jenis rangkaian tidak diketahui"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"data mudah alih"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-my/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-my/strings.xml
new file mode 100644
index 0000000..50590fa
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-my/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"ဝိုင်ဖိုင်ကွန်ရက်သို့ လက်မှတ်ထိုးဝင်ပါ"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"ကွန်ယက်သို့ လက်မှတ်ထိုးဝင်ရန်"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> တွင် အင်တာနက်အသုံးပြုခွင့် မရှိပါ"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"အခြားရွေးချယ်စရာများကိုကြည့်ရန် တို့ပါ"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"မိုဘိုင်းကွန်ရက်တွင် အင်တာနက်ချိတ်ဆက်မှု မရှိပါ"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"ကွန်ရက်တွင် အင်တာနက်အသုံးပြုခွင့် မရှိပါ"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"သီးသန့် ဒီအန်အက်စ် (DNS) ဆာဗာကို သုံး၍မရပါ။"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> တွင် ချိတ်ဆက်မှုကို ကန့်သတ်ထားသည်"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"မည်သို့ပင်ဖြစ်စေ ချိတ်ဆက်ရန် တို့ပါ"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> သို့ ပြောင်းလိုက်ပြီ"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ဖြင့် အင်တာနက် အသုံးမပြုနိုင်သည့်အချိန်တွင် စက်ပစ္စည်းသည် <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ကို သုံးပါသည်။ ဒေတာသုံးစွဲခ ကျသင့်နိုင်ပါသည်။"</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> မှ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> သို့ ပြောင်းလိုက်ပြီ"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"အမည်မသိကွန်ရက်အမျိုးအစား"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"မိုဘိုင်းဒေတာ"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"ဘလူးတုသ်"</item>
+    <item msgid="1616528372438698248">"အီသာနက်"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-nb/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-nb/strings.xml
new file mode 100644
index 0000000..b89d198
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-nb/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Logg på Wi-Fi-nettverket"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Logg på nettverk"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har ingen internettilkobling"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Trykk for å få alternativer"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilnettverket har ingen internettilgang"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Nettverket har ingen internettilgang"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Den private DNS-tjeneren kan ikke nås"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har begrenset tilkobling"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Trykk for å koble til likevel"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Byttet til <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Enheten bruker <xliff:g id="NEW_NETWORK">%1$s</xliff:g> når <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ikke har Internett-tilgang. Avgifter kan påløpe."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Byttet fra <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> til <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"en ukjent nettverkstype"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"mobildata"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ne/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ne/strings.xml
new file mode 100644
index 0000000..bdcfa3b
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ne/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi नेटवर्कमा साइन इन गर्नुहोस्"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"सञ्जालमा साइन इन गर्नुहोस्"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> को इन्टरनेटमाथि पहुँच छैन"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"विकल्पहरूका लागि ट्याप गर्नुहोस्"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"मोबाइल नेटवर्कको इन्टरनेटमाथि पहुँच छैन"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"नेटवर्कको इन्टरनेटमाथि पहुँच छैन"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"निजी DNS सर्भरमाथि पहुँच प्राप्त गर्न सकिँदैन"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> को जडान सीमित छ"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"जसरी भए पनि जडान गर्न ट्याप गर्नुहोस्"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> मा बदल्नुहोस्"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> मार्फत इन्टरनेटमाथि पहुँच राख्न नसकेको अवस्थामा यन्त्रले <xliff:g id="NEW_NETWORK">%1$s</xliff:g> प्रयोग गर्दछ। शुल्क लाग्न सक्छ।"</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> बाट <xliff:g id="NEW_NETWORK">%2$s</xliff:g> मा परिवर्तन गरियो"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"नेटवर्कको कुनै अज्ञात प्रकार"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"मोबाइल डेटा"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"ब्लुटुथ"</item>
+    <item msgid="1616528372438698248">"इथरनेट"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-nl/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-nl/strings.xml
new file mode 100644
index 0000000..8ecff6e
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-nl/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Inloggen bij wifi-netwerk"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Inloggen bij netwerk"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> heeft geen internettoegang"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Tik voor opties"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Mobiel netwerk heeft geen internettoegang"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Netwerk heeft geen internettoegang"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Geen toegang tot privé-DNS-server"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> heeft beperkte connectiviteit"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tik om toch verbinding te maken"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Overgeschakeld naar <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Apparaat gebruikt <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wanneer <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> geen internetverbinding heeft. Er kunnen kosten in rekening worden gebracht."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Overgeschakeld van <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> naar <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"een onbekend netwerktype"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"mobiele data"</item>
+    <item msgid="5520925862115353992">"Wifi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-or/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-or/strings.xml
new file mode 100644
index 0000000..6ec1f9d
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-or/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"ୱାଇ-ଫାଇ ନେଟୱର୍କରେ ସାଇନ୍‍-ଇନ୍‍ କରନ୍ତୁ"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"ନେଟ୍‌ୱର୍କରେ ସାଇନ୍‍ ଇନ୍‍ କରନ୍ତୁ"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>ର ଇଣ୍ଟର୍ନେଟ୍ ଆକ୍ସେସ୍ ନାହିଁ"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"ବିକଳ୍ପ ପାଇଁ ଟାପ୍‍ କରନ୍ତୁ"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"ମୋବାଇଲ୍ ନେଟ୍‌ୱାର୍କରେ ଇଣ୍ଟର୍ନେଟ୍ ଆକ୍ସେସ୍ ନାହିଁ"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"ନେଟ୍‌ୱାର୍କରେ ଇଣ୍ଟର୍ନେଟ୍ ଆକ୍ସେସ୍ ନାହିଁ"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"ବ୍ୟକ୍ତିଗତ DNS ସର୍ଭର୍ ଆକ୍ସେସ୍ କରିହେବ ନାହିଁ"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>ର ସୀମିତ ସଂଯୋଗ ଅଛି"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"ତଥାପି ଯୋଗାଯୋଗ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>କୁ ବଦଳାଗଲା"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>ର ଇଣ୍ଟରନେଟ୍‍ ଆକ୍ସେସ୍ ନଥିବାବେଳେ ଡିଭାଇସ୍‍ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ବ୍ୟବହାର କରିଥାଏ। ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ।"</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ରୁ <xliff:g id="NEW_NETWORK">%2$s</xliff:g>କୁ ବଦଳାଗଲା"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"ଏକ ଅଜଣା ନେଟ୍‌ୱର୍କ ପ୍ରକାର"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"ମୋବାଇଲ୍‌ ଡାଟା"</item>
+    <item msgid="5520925862115353992">"ୱାଇ-ଫାଇ"</item>
+    <item msgid="1055487873974272842">"ବ୍ଲୁଟୁଥ"</item>
+    <item msgid="1616528372438698248">"ଇଥରନେଟ୍‌"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-pa/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-pa/strings.xml
new file mode 100644
index 0000000..e948193
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-pa/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ \'ਤੇ ਸਾਈਨ-ਇਨ ਕਰੋ"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"ਨੈੱਟਵਰਕ \'ਤੇ ਸਾਈਨ-ਇਨ ਕਰੋ"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"ਵਿਕਲਪਾਂ ਲਈ ਟੈਪ ਕਰੋ"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"ਮੋਬਾਈਲ ਨੈੱਟਵਰਕ ਕੋਲ ਇੰਟਰਨੈੱਟ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਹੈ"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"ਨੈੱਟਵਰਕ ਕੋਲ ਇੰਟਰਨੈੱਟ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਹੈ"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"ਨਿੱਜੀ ਡੋਮੇਨ ਨਾਮ ਪ੍ਰਣਾਲੀ (DNS) ਸਰਵਰ \'ਤੇ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕੀ"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ਕੋਲ ਸੀਮਤ ਕਨੈਕਟੀਵਿਟੀ ਹੈ"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"ਫਿਰ ਵੀ ਕਨੈਕਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"ਬਦਲਕੇ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ਲਿਆਂਦਾ ਗਿਆ"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ਦੀ ਇੰਟਰਨੈੱਟ \'ਤੇ ਪਹੁੰਚ ਨਾ ਹੋਣ \'ਤੇ ਡੀਵਾਈਸ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰਦਾ ਹੈ। ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ।"</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ਤੋਂ ਬਦਲਕੇ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> \'ਤੇ ਕੀਤਾ ਗਿਆ"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"ਇੱਕ ਅਗਿਆਤ ਨੈੱਟਵਰਕ ਕਿਸਮ"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"ਮੋਬਾਈਲ ਡਾਟਾ"</item>
+    <item msgid="5520925862115353992">"ਵਾਈ-ਫਾਈ"</item>
+    <item msgid="1055487873974272842">"ਬਲੂਟੁੱਥ"</item>
+    <item msgid="1616528372438698248">"ਈਥਰਨੈੱਟ"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-pl/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-pl/strings.xml
new file mode 100644
index 0000000..038328f
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-pl/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Zaloguj się w sieci Wi-Fi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Zaloguj się do sieci"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nie ma dostępu do internetu"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Kliknij, by wyświetlić opcje"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Sieć komórkowa nie ma dostępu do internetu"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Sieć nie ma dostępu do internetu"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Brak dostępu do prywatnego serwera DNS"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ma ograniczoną łączność"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Kliknij, by mimo to nawiązać połączenie"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Zmieniono na połączenie typu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Urządzenie korzysta z połączenia typu <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, gdy <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nie dostępu do internetu. Mogą zostać naliczone opłaty."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Przełączono z połączenia typu <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na <xliff:g id="NEW_NETWORK">%2$s</xliff:g>."</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"nieznany typ sieci"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"mobilna transmisja danych"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-pt-rBR/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..fe37405
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-pt-rBR/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Fazer login na rede Wi-Fi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Fazer login na rede"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> não tem acesso à Internet"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Toque para ver opções"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"A rede móvel não tem acesso à Internet"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"A rede não tem acesso à Internet"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Não é possível acessar o servidor DNS privado"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tem conectividade limitada"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Toque para conectar mesmo assim"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Alternado para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"O dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Esse serviço pode ser cobrado."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Alternado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"um tipo de rede desconhecido"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"dados móveis"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-pt-rPT/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..69060f7
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-pt-rPT/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Iniciar sessão na rede Wi-Fi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Início de sessão na rede"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> não tem acesso à Internet"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Toque para obter mais opções"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"A rede móvel não tem acesso à Internet"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"A rede não tem acesso à Internet"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Não é possível aceder ao servidor DNS."</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tem conetividade limitada."</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Toque para ligar mesmo assim."</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Mudou para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"O dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Podem aplicar-se custos."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Mudou de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"um tipo de rede desconhecido"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"dados móveis"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-pt/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-pt/strings.xml
new file mode 100644
index 0000000..fe37405
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-pt/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Fazer login na rede Wi-Fi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Fazer login na rede"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> não tem acesso à Internet"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Toque para ver opções"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"A rede móvel não tem acesso à Internet"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"A rede não tem acesso à Internet"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Não é possível acessar o servidor DNS privado"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tem conectividade limitada"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Toque para conectar mesmo assim"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Alternado para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"O dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Esse serviço pode ser cobrado."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Alternado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"um tipo de rede desconhecido"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"dados móveis"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ro/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ro/strings.xml
new file mode 100644
index 0000000..227b7be
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ro/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Conectați-vă la rețeaua Wi-Fi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Conectați-vă la rețea"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nu are acces la internet"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Atingeți pentru opțiuni"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Rețeaua mobilă nu are acces la internet"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Rețeaua nu are acces la internet"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Serverul DNS privat nu poate fi accesat"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> are conectivitate limitată"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Atingeți pentru a vă conecta oricum"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"S-a comutat la <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Dispozitivul folosește <xliff:g id="NEW_NETWORK">%1$s</xliff:g> când <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nu are acces la internet. Se pot aplica taxe."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"S-a comutat de la <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> la <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"un tip de rețea necunoscut"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"date mobile"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ru/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ru/strings.xml
new file mode 100644
index 0000000..18acf81
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ru/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Подключение к Wi-Fi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Регистрация в сети"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"Сеть \"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>\" не подключена к Интернету"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Нажмите, чтобы показать варианты."</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Мобильная сеть не подключена к Интернету"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Сеть не подключена к Интернету"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Доступа к частному DNS-серверу нет."</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"Подключение к сети \"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>\" ограничено"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Нажмите, чтобы подключиться"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Новое подключение: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Устройство использует <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, если подключение к сети <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> недоступно. Может взиматься плата за передачу данных."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Устройство отключено от сети <xliff:g id="NEW_NETWORK">%2$s</xliff:g> и теперь использует <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"неизвестный тип сети"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"мобильный Интернет"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-si/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-si/strings.xml
new file mode 100644
index 0000000..6307c2b
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-si/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi ජාලයට පුරනය වන්න"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"ජාලයට පුරනය වන්න"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> හට අන්තර්ජාල ප්‍රවේශය නැත"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"විකල්ප සඳහා තට්ටු කරන්න"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"ජංගම ජාලවලට අන්තර්ජාල ප්‍රවේශය නැත"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"ජාලයට අන්තර්ජාල ප්‍රවේශය නැත"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"පුද්ගලික DNS සේවාදායකයට ප්‍රවේශ වීමට නොහැකිය"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> හට සීමිත සබැඳුම් හැකියාවක් ඇත"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"කෙසේ වෙතත් ඉදිරියට යාමට තට්ටු කරන්න"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> වෙත මාරු විය"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"උපාංගය <xliff:g id="NEW_NETWORK">%1$s</xliff:g> <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> සඳහා අන්තර්ජාල ප්‍රවේශය නැති විට භාවිත කරයි. ගාස්තු අදාළ විය හැකිය."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> සිට <xliff:g id="NEW_NETWORK">%2$s</xliff:g> වෙත මාරු විය"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"නොදන්නා ජාල වර්ගයකි"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"ජංගම දත්ත"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"බ්ලූටූත්"</item>
+    <item msgid="1616528372438698248">"ඊතර්නෙට්"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-sk/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sk/strings.xml
new file mode 100644
index 0000000..e894fef
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sk/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Prihlásiť sa do siete Wi‑Fi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Prihlásenie do siete"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nemá prístup k internetu"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Klepnutím získate možnosti"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilná sieť nemá prístup k internetu"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Sieť nemá prístup k internetu"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"K súkromnému serveru DNS sa nepodarilo získať prístup"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> má obmedzené pripojenie"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Ak sa chcete aj napriek tomu pripojiť, klepnite"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Prepnuté na sieť: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Keď <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nemá prístup k internetu, zariadenie používa <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Môžu sa účtovať poplatky."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Prepnuté zo siete <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na sieť <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"neznámy typ siete"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"mobilné dáta"</item>
+    <item msgid="5520925862115353992">"Wi‑Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-sl/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sl/strings.xml
new file mode 100644
index 0000000..954b324
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sl/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Prijavite se v omrežje Wi-Fi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Prijava v omrežje"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"Omrežje <xliff:g id="NETWORK_SSID">%1$s</xliff:g> nima dostopa do interneta"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Dotaknite se za možnosti"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilno omrežje nima dostopa do interneta"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Omrežje nima dostopa do interneta"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Do zasebnega strežnika DNS ni mogoče dostopati"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"Povezljivost omrežja <xliff:g id="NETWORK_SSID">%1$s</xliff:g> je omejena"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Dotaknite se, da kljub temu vzpostavite povezavo"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Preklopljeno na omrežje vrste <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Naprava uporabi omrežje vrste <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, ko omrežje vrste <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nima dostopa do interneta. Prenos podatkov se lahko zaračuna."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Preklopljeno z omrežja vrste <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na omrežje vrste <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"neznana vrsta omrežja"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"prenos podatkov v mobilnem omrežju"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-sq/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sq/strings.xml
new file mode 100644
index 0000000..bd5d052
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sq/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Identifikohu në rrjetin Wi-Fi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Identifikohu në rrjet"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nuk ka qasje në internet"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Trokit për opsionet"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Rrjeti celular nuk ka qasje në internet"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Rrjeti nuk ka qasje në internet"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Serveri privat DNS nuk mund të qaset"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ka lidhshmëri të kufizuar"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Trokit për t\'u lidhur gjithsesi"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Kaloi te <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Pajisja përdor <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kur <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nuk ka qasje në internet. Mund të zbatohen tarifa."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Kaloi nga <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> te <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"një lloj rrjeti i panjohur"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"të dhënat celulare"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Eternet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-sr/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sr/strings.xml
new file mode 100644
index 0000000..8bedbff
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sr/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Пријављивање на WiFi мрежу"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Пријавите се на мрежу"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> нема приступ интернету"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Додирните за опције"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Мобилна мрежа нема приступ интернету"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Мрежа нема приступ интернету"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Приступ приватном DNS серверу није успео"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> има ограничену везу"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Додирните да бисте се ипак повезали"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Прешли сте на тип мреже <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Уређај користи тип мреже <xliff:g id="NEW_NETWORK">%1$s</xliff:g> када тип мреже <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> нема приступ интернету. Можда ће се наплаћивати трошкови."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Прешли сте са типа мреже <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на тип мреже <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"непознат тип мреже"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"мобилни подаци"</item>
+    <item msgid="5520925862115353992">"WiFi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Етернет"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-sv/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sv/strings.xml
new file mode 100644
index 0000000..b3f1763
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sv/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Logga in på ett Wi-Fi-nätverk"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Logga in på nätverket"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har ingen internetanslutning"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Tryck för alternativ"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilnätverket har ingen internetanslutning"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Nätverket har ingen internetanslutning"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Det går inte att komma åt den privata DNS-servern."</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har begränsad anslutning"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tryck för att ansluta ändå"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Byte av nätverk till <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> används på enheten när det inte finns internetåtkomst via <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>. Avgifter kan tillkomma."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Byte av nätverk från <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> till <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"en okänd nätverkstyp"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"mobildata"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-sw/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sw/strings.xml
new file mode 100644
index 0000000..9674654
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sw/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Ingia kwa mtandao wa Wi-Fi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Ingia katika mtandao"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> haina uwezo wa kufikia intaneti"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Gusa ili upate chaguo"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Mtandao wa simu hauna uwezo wa kufikia intaneti"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Mtandao hauna uwezo wa kufikia intaneti"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Seva ya faragha ya DNS haiwezi kufikiwa"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ina muunganisho unaofikia huduma chache."</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Gusa ili uunganishe tu"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Sasa inatumia <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Kifaa hutumia <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wakati <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> haina intaneti. Huenda ukalipishwa."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Imebadilisha mtandao kutoka <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na sasa inatumia <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"aina ya mtandao isiyojulikana"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"data ya simu"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethaneti"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ta/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ta/strings.xml
new file mode 100644
index 0000000..12604cb
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ta/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"வைஃபை நெட்வொர்க்கில் உள்நுழையவும்"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"நெட்வொர்க்கில் உள்நுழையவும்"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> நெட்வொர்க்கிற்கு இணைய அணுகல் இல்லை"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"விருப்பங்களுக்கு, தட்டவும்"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"மொபைல் நெட்வொர்க்கிற்கு இணைய அணுகல் இல்லை"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"நெட்வொர்க்கிற்கு இணைய அணுகல் இல்லை"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"தனிப்பட்ட DNS சேவையகத்தை அணுக இயலாது"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> வரம்பிற்கு உட்பட்ட இணைப்புநிலையைக் கொண்டுள்ளது"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"எப்படியேனும் இணைப்பதற்குத் தட்டவும்"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>க்கு மாற்றப்பட்டது"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> நெட்வொர்க்கில் இண்டர்நெட் அணுகல் இல்லாததால், சாதனமானது <xliff:g id="NEW_NETWORK">%1$s</xliff:g> நெட்வொர்க்கைப் பயன்படுத்துகிறது. கட்டணங்கள் விதிக்கப்படலாம்."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> இலிருந்து <xliff:g id="NEW_NETWORK">%2$s</xliff:g>க்கு மாற்றப்பட்டது"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"தெரியாத நெட்வொர்க் வகை"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"மொபைல் டேட்டா"</item>
+    <item msgid="5520925862115353992">"வைஃபை"</item>
+    <item msgid="1055487873974272842">"புளூடூத்"</item>
+    <item msgid="1616528372438698248">"ஈத்தர்நெட்"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-te/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-te/strings.xml
new file mode 100644
index 0000000..84a8640
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-te/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi నెట్‌వర్క్‌కి సైన్ ఇన్ చేయండి"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"నెట్‌వర్క్‌కి సైన్ ఇన్ చేయండి"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>కి ఇంటర్నెట్ యాక్సెస్ లేదు"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"ఎంపికల కోసం నొక్కండి"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"మొబైల్ నెట్‌వర్క్‌కు ఇంటర్నెట్ యాక్సెస్ లేదు"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"నెట్‌వర్క్‌కు ఇంటర్నెట్ యాక్సెస్ లేదు"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"ప్రైవేట్ DNS సర్వర్‌ను యాక్సెస్ చేయడం సాధ్యపడదు"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> పరిమిత కనెక్టివిటీని కలిగి ఉంది"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"ఏదేమైనా కనెక్ట్ చేయడానికి నొక్కండి"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>కి మార్చబడింది"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"పరికరం <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>కి ఇంటర్నెట్ యాక్సెస్ లేనప్పుడు <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ని ఉపయోగిస్తుంది. ఛార్జీలు వర్తించవచ్చు."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> నుండి <xliff:g id="NEW_NETWORK">%2$s</xliff:g>కి మార్చబడింది"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"తెలియని నెట్‌వర్క్ రకం"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"మొబైల్ డేటా"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"బ్లూటూత్"</item>
+    <item msgid="1616528372438698248">"ఈథర్‌నెట్"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-th/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-th/strings.xml
new file mode 100644
index 0000000..1616e51
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-th/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"ลงชื่อเข้าใช้เครือข่าย WiFi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"ลงชื่อเข้าใช้เครือข่าย"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> เข้าถึงอินเทอร์เน็ตไม่ได้"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"แตะเพื่อดูตัวเลือก"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"เครือข่ายมือถือไม่มีการเข้าถึงอินเทอร์เน็ต"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"เครือข่ายไม่มีการเข้าถึงอินเทอร์เน็ต"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"เข้าถึงเซิร์ฟเวอร์ DNS ไม่ได้"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> มีการเชื่อมต่อจำกัด"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"แตะเพื่อเชื่อมต่อ"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"เปลี่ยนเป็น <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"อุปกรณ์จะใช้ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> เมื่อ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> เข้าถึงอินเทอร์เน็ตไม่ได้ โดยอาจมีค่าบริการ"</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"เปลี่ยนจาก <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> เป็น <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"ประเภทเครือข่ายที่ไม่รู้จัก"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"เน็ตมือถือ"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"บลูทูธ"</item>
+    <item msgid="1616528372438698248">"อีเทอร์เน็ต"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-tl/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-tl/strings.xml
new file mode 100644
index 0000000..3bf1ce4
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-tl/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Mag-sign in sa Wi-Fi network"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Mag-sign in sa network"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"Walang access sa internet ang <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"I-tap para sa mga opsyon"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Walang access sa internet ang mobile network"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Walang access sa internet ang network"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Hindi ma-access ang pribadong DNS server"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"Limitado ang koneksyon ng <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"I-tap para kumonekta pa rin"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Lumipat sa <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Ginagamit ng device ang <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kapag walang access sa internet ang <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>. Maaaring may mga malapat na singilin."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Lumipat sa <xliff:g id="NEW_NETWORK">%2$s</xliff:g> mula sa <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"isang hindi kilalang uri ng network"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"mobile data"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-tr/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-tr/strings.xml
new file mode 100644
index 0000000..5c326e5
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-tr/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Kablosuz ağda oturum açın"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Ağda oturum açın"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ağının internet bağlantısı yok"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Seçenekler için dokunun"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Mobil ağın internet bağlantısı yok"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Ağın internet bağlantısı yok"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Gizli DNS sunucusuna erişilemiyor"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> sınırlı bağlantıya sahip"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Yine de bağlanmak için dokunun"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ağına geçildi"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ağının internet erişimi olmadığında cihaz <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ağını kullanır. Bunun için ödeme alınabilir."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ağından <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ağına geçildi"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"bilinmeyen ağ türü"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"mobil veri"</item>
+    <item msgid="5520925862115353992">"Kablosuz"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-uk/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-uk/strings.xml
new file mode 100644
index 0000000..d1382da
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-uk/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Вхід у мережу Wi-Fi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Вхід у мережу"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"Мережа <xliff:g id="NETWORK_SSID">%1$s</xliff:g> не має доступу до Інтернету"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Торкніться, щоб відкрити опції"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Мобільна мережа не має доступу до Інтернету"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Мережа не має доступу до Інтернету"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Немає доступу до приватного DNS-сервера"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"Підключення до мережі <xliff:g id="NETWORK_SSID">%1$s</xliff:g> обмежено"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Натисніть, щоб усе одно підключитися"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Пристрій перейшов на мережу <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Коли мережа <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> не має доступу до Інтернету, використовується <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Може стягуватися плата."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Пристрій перейшов з мережі <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на мережу <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"невідомий тип мережі"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"мобільне передавання даних"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"Мережа VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ur/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ur/strings.xml
new file mode 100644
index 0000000..3c031ad
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ur/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"‏Wi-Fi نیٹ ورک میں سائن ان کریں"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"نیٹ ورک میں سائن ان کریں"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> کو انٹرنیٹ تک رسائی حاصل نہیں ہے"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"اختیارات کیلئے تھپتھپائیں"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"موبائل نیٹ ورک کو انٹرنیٹ تک رسائی حاصل نہیں ہے"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"نیٹ ورک کو انٹرنیٹ تک رسائی حاصل نہیں ہے"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"‏نجی DNS سرور تک رسائی حاصل نہیں کی جا سکی"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> کی کنیکٹوٹی محدود ہے"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"بہر حال منسلک کرنے کے لیے تھپتھپائیں"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> پر سوئچ ہو گیا"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"جب <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> کو انٹرنیٹ تک رسائی نہیں ہوتی ہے تو آلہ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> کا استعمال کرتا ہے۔ چارجز لاگو ہو سکتے ہیں۔"</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> سے <xliff:g id="NEW_NETWORK">%2$s</xliff:g> پر سوئچ ہو گیا"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"نیٹ ورک کی نامعلوم قسم"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"موبائل ڈیٹا"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"بلوٹوتھ"</item>
+    <item msgid="1616528372438698248">"ایتھرنیٹ"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-uz/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-uz/strings.xml
new file mode 100644
index 0000000..7518db3
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-uz/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi tarmoqqa kirish"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Tarmoqqa kirish"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nomli tarmoqda internetga ruxsati yoʻq"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Variantlarni ko‘rsatish uchun bosing"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Mobil tarmoq internetga ulanmagan"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Tarmoq internetga ulanmagan"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Xususiy DNS server ishlamayapti"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nomli tarmoqda aloqa cheklangan"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Baribir ulash uchun bosing"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Yangi ulanish: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Agar <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tarmoqda internet uzilsa, qurilma <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ga ulanadi. Sarflangan trafik uchun haq olinishi mumkin."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> tarmog‘idan <xliff:g id="NEW_NETWORK">%2$s</xliff:g> tarmog‘iga o‘tildi"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"noma’lum tarmoq turi"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"mobil internet"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-vi/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-vi/strings.xml
new file mode 100644
index 0000000..d2284d4
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-vi/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Đăng nhập vào mạng Wi-Fi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Đăng nhập vào mạng"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> không có quyền truy cập Internet"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Nhấn để biết tùy chọn"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Mạng di động không có quyền truy cập Internet"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Mạng không có quyền truy cập Internet"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Không thể truy cập máy chủ DNS riêng tư"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> có khả năng kết nối giới hạn"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Nhấn để tiếp tục kết nối"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Đã chuyển sang <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Thiết bị sử dụng <xliff:g id="NEW_NETWORK">%1$s</xliff:g> khi <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> không có quyền truy cập Internet. Bạn có thể phải trả phí."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Đã chuyển từ <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> sang <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"loại mạng không xác định"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"dữ liệu di động"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"Bluetooth"</item>
+    <item msgid="1616528372438698248">"Ethernet"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-zh-rCN/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..813482b
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-zh-rCN/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"登录到WLAN网络"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"登录到网络"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> 无法访问互联网"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"点按即可查看相关选项"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"此移动网络无法访问互联网"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"此网络无法访问互联网"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"无法访问私人 DNS 服务器"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> 的连接受限"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"点按即可继续连接"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"已切换至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"设备会在<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>无法访问互联网时使用<xliff:g id="NEW_NETWORK">%1$s</xliff:g>(可能需要支付相应的费用)。"</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"已从<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>切换至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"未知网络类型"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"移动数据"</item>
+    <item msgid="5520925862115353992">"WLAN"</item>
+    <item msgid="1055487873974272842">"蓝牙"</item>
+    <item msgid="1616528372438698248">"以太网"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-zh-rHK/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..676404f
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-zh-rHK/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"登入 Wi-Fi 網絡"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"登入網絡"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>未有連接至互聯網"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"輕按即可查看選項"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"流動網絡並未連接互聯網"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"網絡並未連接互聯網"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"無法存取私人 DNS 伺服器"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>連線受限"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"仍要輕按以連結至此網絡"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"已切換至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"裝置會在 <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> 無法連線至互聯網時使用<xliff:g id="NEW_NETWORK">%1$s</xliff:g> (可能需要支付相關費用)。"</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"已從<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>切換至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"不明網絡類型"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"流動數據"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"藍牙"</item>
+    <item msgid="1616528372438698248">"以太網"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-zh-rTW/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..f355138
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-zh-rTW/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"登入 Wi-Fi 網路"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"登入網路"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> 沒有網際網路連線"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"輕觸即可查看選項"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"這個行動網路沒有網際網路連線"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"這個網路沒有網際網路連線"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"無法存取私人 DNS 伺服器"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> 的連線能力受限"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"輕觸即可繼續連線"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"已切換至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"裝置會在無法連上「<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>」時切換至「<xliff:g id="NEW_NETWORK">%1$s</xliff:g>」(可能需要支付相關費用)。"</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"已從 <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> 切換至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"不明的網路類型"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"行動數據"</item>
+    <item msgid="5520925862115353992">"Wi-Fi"</item>
+    <item msgid="1055487873974272842">"藍牙"</item>
+    <item msgid="1616528372438698248">"乙太網路"</item>
+    <item msgid="9177085807664964627">"VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-zu/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-zu/strings.xml
new file mode 100644
index 0000000..55fefb7
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-zu/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_available_sign_in" msgid="381054692557675237">"Ngena ngemvume kunethiwekhi ye-Wi-Fi"</string>
+    <string name="network_available_sign_in" msgid="1520342291829283114">"Ngena ngemvume kunethiwekhi"</string>
+    <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+    <string name="wifi_no_internet" msgid="1386911698276448061">"I-<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ayinakho ukufinyelela kwe-inthanethi"</string>
+    <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Thepha ukuze uthole izinketho"</string>
+    <string name="mobile_no_internet" msgid="4014455157529909781">"Inethiwekhi yeselula ayinakho ukufinyelela kwe-inthanethi"</string>
+    <string name="other_networks_no_internet" msgid="6698711684200067033">"Inethiwekhi ayinakho ukufinyelela kwenethiwekhi"</string>
+    <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Iseva eyimfihlo ye-DNS ayikwazi ukufinyelelwa"</string>
+    <string name="network_partial_connectivity" msgid="4791024923851432291">"I-<xliff:g id="NETWORK_SSID">%1$s</xliff:g> inokuxhumeka okukhawulelwe"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Thepha ukuze uxhume noma kunjalo"</string>
+    <string name="network_switch_metered" msgid="1531869544142283384">"Kushintshelwe ku-<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+    <string name="network_switch_metered_detail" msgid="1358296010128405906">"Idivayisi isebenzisa i-<xliff:g id="NEW_NETWORK">%1$s</xliff:g> uma i-<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> inganakho ukufinyelela kwe-inthanethi. Kungasebenza izindleko."</string>
+    <string name="network_switch_metered_toast" msgid="501662047275723743">"Kushintshelewe kusuka ku-<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> kuya ku-<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+    <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"uhlobo olungaziwa lwenethiwekhi"</string>
+  <string-array name="network_switch_type_name">
+    <item msgid="2255670471736226365">"idatha yeselula"</item>
+    <item msgid="5520925862115353992">"I-Wi-Fi"</item>
+    <item msgid="1055487873974272842">"I-Bluetooth"</item>
+    <item msgid="1616528372438698248">"I-Ethernet"</item>
+    <item msgid="9177085807664964627">"I-VPN"</item>
+  </string-array>
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values/config.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values/config.xml
index 06c8192..71674e4 100644
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values/config.xml
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values/config.xml
@@ -52,4 +52,41 @@
         <item>12,60000</item><!-- mobile_cbs -->
     </string-array>
 
-</resources>
\ No newline at end of file
+    <!-- Whether the APF Filter in the device should filter out IEEE 802.3 Frames
+         Those frames are identified by the field Eth-type having values
+         less than 0x600 -->
+    <bool translatable="false" name="config_apfDrop802_3Frames">true</bool>
+
+    <!-- An array of Denylisted EtherType, packets with EtherTypes within this array
+         will be dropped
+         TODO: need to put proper values, these are for testing purposes only -->
+    <integer-array translatable="false" name="config_apfEthTypeDenyList">
+        <item>0x88A2</item>
+        <item>0x88A4</item>
+        <item>0x88B8</item>
+        <item>0x88CD</item>
+        <item>0x88E3</item>
+    </integer-array>
+
+    <!-- Default supported concurrent socket keepalive slots per transport type, used by
+         ConnectivityManager.createSocketKeepalive() for calculating the number of keepalive
+         offload slots that should be reserved for privileged access. This string array should be
+         overridden by the device to present the capability of creating socket keepalives. -->
+    <!-- An Array of "[NetworkCapabilities.TRANSPORT_*],[supported keepalives] -->
+    <string-array translatable="false" name="config_networkSupportedKeepaliveCount">
+        <item>0,1</item>
+        <item>1,3</item>
+    </string-array>
+
+
+    <!-- Default value for ConnectivityManager.getMultipathPreference() on metered networks. Actual
+         device behaviour is controlled by the metered multipath preference in
+         ConnectivitySettingsManager. This is the default value of that setting. -->
+    <integer translatable="false" name="config_networkMeteredMultipathPreference">0</integer>
+
+    <!-- Whether the device should automatically switch away from Wi-Fi networks that lose
+         Internet access. Actual device behaviour is controlled by
+         Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. -->
+    <integer translatable="false" name="config_networkAvoidBadWifi">1</integer>
+
+</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values/overlayable.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values/overlayable.xml
index da8aee5..25e19ce 100644
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values/overlayable.xml
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values/overlayable.xml
@@ -21,6 +21,11 @@
             <item type="string" name="config_networkCaptivePortalServerUrl"/>
             <item type="integer" name="config_networkTransitionTimeout"/>
             <item type="array" name="config_wakeonlan_supported_interfaces"/>
+            <item type="bool" name="config_apfDrop802_3Frames"/>
+            <item type="array" name="config_apfEthTypeDenyList"/>
+            <item type="integer" name="config_networkMeteredMultipathPreference"/>
+            <item type="array" name="config_networkSupportedKeepaliveCount"/>
+            <item type="integer" name="config_networkAvoidBadWifi"/>
 
         </policy>
     </overlayable>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values/strings.xml
index 2c7b992..b2fa5f5 100644
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values/strings.xml
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values/strings.xml
@@ -14,9 +14,61 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- The System Connectivity Resources package is an internal system package that provides
          configuration values for system networking that were pre-configured in the device. This
          is the name of the package to display in the list of system apps. [CHAR LIMIT=40] -->
     <string name="connectivityResourcesAppLabel">System Connectivity Resources</string>
-</resources>
\ No newline at end of file
+
+    <!-- A notification is shown when a wifi captive portal network is detected.  This is the notification's title. -->
+    <string name="wifi_available_sign_in">Sign in to Wi-Fi network</string>
+
+    <!-- A notification is shown when a captive portal network is detected.  This is the notification's title. -->
+    <string name="network_available_sign_in">Sign in to network</string>
+
+    <!-- A notification is shown when a captive portal network is detected.  This is the notification's message. -->
+    <string name="network_available_sign_in_detailed"><xliff:g id="network_ssid">%1$s</xliff:g></string>
+
+    <!-- A notification is shown when the user connects to a Wi-Fi network and the system detects that that network has no Internet access. This is the notification's title. -->
+    <string name="wifi_no_internet"><xliff:g id="network_ssid" example="GoogleGuest">%1$s</xliff:g> has no internet access</string>
+
+    <!-- A notification is shown when the user connects to a Wi-Fi network and the system detects that that network has no Internet access. This is the notification's message. -->
+    <string name="wifi_no_internet_detailed">Tap for options</string>
+
+    <!-- A notification is shown when the user connects to a mobile network without internet access. This is the notification's title. -->
+    <string name="mobile_no_internet">Mobile network has no internet access</string>
+
+    <!-- A notification is shown when the user connects to a non-mobile and non-wifi network without internet access. This is the notification's title. -->
+    <string name="other_networks_no_internet">Network has no internet access</string>
+
+    <!-- A notification is shown when connected network without internet due to private dns validation failed. This is the notification's message. [CHAR LIMIT=NONE] -->
+    <string name="private_dns_broken_detailed">Private DNS server cannot be accessed</string>
+
+    <!-- A notification is shown when the user connects to a network that doesn't have access to some services (e.g. Push notifications may not work). This is the notification's title. [CHAR LIMIT=50] -->
+    <string name="network_partial_connectivity"><xliff:g id="network_ssid" example="GoogleGuest">%1$s</xliff:g> has limited connectivity</string>
+
+    <!-- A notification is shown when the user connects to a network that doesn't have access to some services (e.g. Push notifications may not work). This is the notification's message. [CHAR LIMIT=50] -->
+    <string name="network_partial_connectivity_detailed">Tap to connect anyway</string>
+
+    <!-- A notification might be shown if the device switches to another network type (e.g., mobile data) because it detects that the network it was using (e.g., Wi-Fi) has lost Internet connectivity. This is the notification's title. %1$s is the network type that the device switched to, e.g., cellular data. It is one of the strings in the network_switch_type_name array. -->
+    <string name="network_switch_metered">Switched to <xliff:g id="network_type">%1$s</xliff:g></string>
+
+    <!-- A notification might be shown if the device switches to another network type (e.g., mobile data) because it detects that the network it was using (e.g., Wi-Fi) has lost Internet connectivity. This is the notification's message. %1$s is the network that the device switched to, e.g., cellular data. %2$s is the network type the device switched from, e.g., Wi-Fi. Both are strings in the network_switch_type_name array. -->
+    <string name="network_switch_metered_detail">Device uses <xliff:g id="new_network">%1$s</xliff:g> when <xliff:g id="previous_network">%2$s</xliff:g> has no internet access. Charges may apply.</string>
+
+    <!-- A toast might be shown if the device switches to another network type (e.g., mobile data) because it detects that the network it was using (e.g., Wi-Fi) has lost Internet connectivity. This is the text of the toast. %1$s is the network that the device switched from, e.g., Wi-Fi. %2$s is the network type the device switched from, e.g., cellular data. Both are strings in the network_switch_type_name array. -->
+    <string name="network_switch_metered_toast">Switched from <xliff:g id="previous_network">%1$s</xliff:g> to <xliff:g id="new_network">%2$s</xliff:g></string>
+
+    <!-- Network type names used in the network_switch_metered and network_switch_metered_detail strings. These must be kept in the sync with the values NetworkCapabilities.TRANSPORT_xxx values, and in the same order. -->
+    <string-array name="network_switch_type_name">
+        <item>mobile data</item>
+        <item>Wi-Fi</item>
+        <item>Bluetooth</item>
+        <item>Ethernet</item>
+        <item>VPN</item>
+    </string-array>
+
+    <!-- Network type name displayed if one of the types is not found in network_switch_type_name. -->
+    <string name="network_switch_type_name_unknown">an unknown network type</string>
+
+</resources>
diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
index 63edc77..4344e94 100644
--- a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
@@ -66,6 +66,8 @@
 
     private static final String INCREMENTAL_DIR = "_delta";
     private static final String FULL_DATA_DIR = "_full";
+    private static final String DEVICE_NAME_FOR_D2D_RESTORE_SET = "D2D";
+    private static final String DEFAULT_DEVICE_NAME_FOR_RESTORE_SET = "flash";
 
     // The currently-active restore set always has the same (nonzero!) token
     private static final long CURRENT_SET_TOKEN = 1;
@@ -603,8 +605,10 @@
         existing[num++] = CURRENT_SET_TOKEN;
 
         RestoreSet[] available = new RestoreSet[num];
+        String deviceName = mParameters.isDeviceTransfer() ? DEVICE_NAME_FOR_D2D_RESTORE_SET
+                : DEFAULT_DEVICE_NAME_FOR_RESTORE_SET;
         for (int i = 0; i < available.length; i++) {
-            available[i] = new RestoreSet("Local disk image", "flash", existing[i]);
+            available[i] = new RestoreSet("Local disk image", deviceName, existing[i]);
         }
         return available;
     }
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index 68ce7d9..d6c66b5 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -17,8 +17,8 @@
 
     // TODO(b/149540986): revert this change.
     static_libs: [
-        // All other dependent components should be put in
-        // "SettingsLibDependenciesWithoutWifiTracker".
+         // All other dependent components should be put in
+         // "SettingsLibDependenciesWithoutWifiTracker".
         "WifiTrackerLib",
     ],
 
@@ -27,10 +27,7 @@
 
     resource_dirs: ["res"],
 
-    srcs: [
-        "src/**/*.java",
-        "src/**/*.kt",
-    ],
+    srcs: ["src/**/*.java", "src/**/*.kt"],
 
     min_sdk_version: "21",
 
diff --git a/packages/SettingsLib/TwoTargetPreference/Android.bp b/packages/SettingsLib/TwoTargetPreference/Android.bp
index f2e79b9..078e8c3 100644
--- a/packages/SettingsLib/TwoTargetPreference/Android.bp
+++ b/packages/SettingsLib/TwoTargetPreference/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: "SettingsLibTwoTargetPreference",
 
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 0ee44f8..7cf8cda 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (rooi-groen)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (blou-geel)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Kleurregstelling"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Verstel hoe kleure op jou toestel vertoon. Dit kan nuttig wees wanneer jy:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Kleure meer akkuraat wil sien&lt;/li&gt; &lt;li&gt; Kleure wil verwyder om jou te help fokus&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Verstel hoe kleure op jou toestel vertoon. Dit kan nuttig wees wanneer jy:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Kleure meer akkuraat wil sien&lt;/li&gt; &lt;li&gt;&amp;nbsp;Kleure wil verwyder om jou te help fokus&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Geneutraliseer deur <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g> oor"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 9fb676f..d3e4d1c 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"ፕሮታኖማሊ (ቀይ-አረንጓዴ)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ትራይታኖማሊ (ሰማያዊ-ቢጫ)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"የቀለም ማስተካከያ"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"ቀለሞች በመሣሪያዎ ላይ እንዴት እንደሚታዩ ያስተካክሉ። የሚከተሉትን ለማድረግ በሚፈልጉበት ጊዜ ይህ ጠቃሚ ሊሆን ይችላል፦&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; ቀለሞችን የበለጠ ትክክለኛ በሆነ መልኩ ለመመልከት&lt;/li&gt; &lt;li&gt; ትኩረት ለማድረግ እንዲረዳዎ ቀለሞችን ለማስወገድ&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"ቀለሞች በመሣሪያዎ ላይ እንዴት እንደሚታዩ ያስተካክሉ። የሚከተሉትን ለማድረግ በሚፈልጉበት ጊዜ ይህ ጠቃሚ ሊሆን ይችላል፦&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;ቀለሞችን የበለጠ ትክክለኛ በሆነ መልኩ ለመመልከት&lt;/li&gt; &lt;li&gt;&amp;nbsp;ትኩረት ለማድረግ እንዲረዳዎ ቀለሞችን ለማስወገድ&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"በ<xliff:g id="TITLE">%1$s</xliff:g> ተሽሯል"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ገደማ ቀርቷል"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index cdb418a..ca613f9 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"غطش الأحمر (الأحمر والأخضر)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"غمش الأزرق (الأزرق والأصفر)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"تصحيح الألوان"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"‏يمكنك تعديل كيفية عرض الألوان على جهازك. يساعدك هذا الخيار عندما تريد تنفيذ ما يلي:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; عرض الألوان بمزيد من الدقة&lt;/li&gt; &lt;li&gt; إزالة الألوان لمساعدتك على التركيز&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"‏يمكنك تعديل كيفية عرض الألوان على جهازك. يساعدك هذا الخيار عندما تريد تنفيذ ما يلي:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;عرض الألوان بمزيد من الدقة&lt;/li&gt; &lt;li&gt;&amp;nbsp;إزالة الألوان لمساعدتك على التركيز&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"تم الاستبدال بـ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"يتبقى <xliff:g id="TIME_REMAINING">%1$s</xliff:g> تقريبًا"</string>
@@ -570,7 +570,7 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"مفعّل"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"يجب إعادة تشغيل جهازك ليتم تطبيق هذا التغيير. يمكنك إعادة التشغيل الآن أو إلغاء التغيير."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"سمّاعة سلكية"</string>
-    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"تفعيل"</string>
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"مفعّلة"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"إيقاف"</string>
     <string name="carrier_network_change_mode" msgid="4257621815706644026">"جارٍ تغيير شبكة مشغِّل شبكة الجوّال."</string>
     <string name="data_connection_3g" msgid="931852552688157407">"شبكة الجيل الثالث"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 442a19d..6037557 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"প্ৰ’টানোমালি (ৰঙা-সেউজীয়া)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ট্ৰাইটান\'মেলী (নীলা-হালধীয়া)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ৰং শুধৰণী"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"আপোনাৰ ডিভাইচত ৰংবোৰ কেনেকৈ প্ৰদৰ্শিত হয় সেয়া মিলাওক। এইটো আপুনি এই কাৰ্য কৰিবলৈ বিচাৰিলে সহায়ক হ\'ব পাৰে:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; ৰং অধিক সঠিককৈ চাবলৈ বিচৰা&lt;/li&gt; &lt;li&gt; আপোনাক মনোযোগ দিয়াত সহায় কৰিবলৈ ৰং আঁতৰোৱা&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"আপোনাৰ ডিভাইচত ৰংবোৰ কেনেকৈ প্ৰদৰ্শিত হয় সেয়া মিলাওক। আপুনি এয়া কৰিবলৈ বিচাৰিলে এইটো সহায়ক হ’ব পাৰে:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;ৰংবোৰ অধিক সঠিকভাৱে চোৱা&lt;/li&gt; &lt;li&gt;&amp;nbsp;আপোনাক মনোনিৱেশ কৰাৰ ক্ষেত্ৰত সহায় কৰিবলৈ ৰং আঁতৰোৱা&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g>ৰ দ্বাৰা অগ্ৰাহ্য কৰা হৈছে"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"প্রায় <xliff:g id="TIME_REMAINING">%1$s</xliff:g> বাকী আছে"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 2b0fa86..97ae192 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaliya (qırmızı-yaşıl)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaliya (göy-sarı)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Rəng düzəlişi"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Cihazınızda rənglərin necə göstərilməsini tənzimləyin. Bu, aşağıdakıları etmək istədikdə faydalı ola bilər:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Rəngləri daha dəqiq görmək&lt;/li&gt; &lt;li&gt; Fokuslanmaq üçün rəngləri ləğv etmək&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Cihazınızda rənglərin necə göstərilməsini tənzimləyin. Bu, aşağıdakıları etmək istədikdə faydalı ola bilər:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Rəngləri daha dəqiq görmək&lt;/li&gt; &lt;li&gt;&amp;nbsp;Fokuslanmaq üçün rəngləri ləğv etmək&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> tərəfindən qəbul edilmir"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Təxminən <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qalıb"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index b318637..6bed4057 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalija (crveno-zeleno)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalija (plavo-žuto)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korekcija boja"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Prilagodite način na koji se boje prikazuju na uređaju. To može da bude korisno kada želite:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; da vam se boje tačnije prikazuju&lt;/li&gt; &lt;li&gt; da uklonite boje kako biste se fokusirali&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Prilagodite način na koji se boje prikazuju na uređaju. To može da bude korisno kada želite:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;da vam se boje tačnije prikazuju&lt;/li&gt; &lt;li&gt;&amp;nbsp;da uklonite boje kako biste se fokusirali&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Zamenjuje ga <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>–<xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Preostalo je oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 950a5ae..029d355 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Пратанамалія (чырвоны-зялёны)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Трытанамалія (сіні-жоўты)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Карэкцыя колеру"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Наладзьце адлюстраванне колераў на экране прылады. Гэта налада можа быць карыснай, калі вы захочаце:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; бачыць колеры больш дакладна;&lt;/li&gt; &lt;li&gt; выдаліць колеры, якія перашкаджаюць вам сканцэнтравацца&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Наладзьце адлюстраванне колераў на экране прылады. Гэта налада можа быць карыснай, калі вы захочаце:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;бачыць колеры больш дакладна;&lt;/li&gt; &lt;li&gt;&amp;nbsp;выдаліць колеры, якія перашкаджаюць вам сканцэнтравацца&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Перавызначаны <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Зараду хопіць прыблізна на <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 9ff2531..032b433 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалия (червено – зелено)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалия (синьо – жълто)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Корекция на цветове"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Коригирайте как цветовете се показват на устройството ви. Това може да бъде полезно, когато искате да:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; видите цветовете по-ясно;&lt;/li&gt; &lt;li&gt; премахнете цветовете, за да се фокусирате.&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Коригирайте как цветовете се показват на устройството ви. Това може да бъде полезно, когато искате:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;да видите цветовете по-ясно;&lt;/li&gt; &lt;li&gt;&amp;nbsp;да премахнете цветовете, за да се фокусирате.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Заменено от „<xliff:g id="TITLE">%1$s</xliff:g>“"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Още около <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 4cc9abf..331dfee 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"প্রোটানোম্যালি (লাল-সবুজ)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ট্রিট্যানোম্যালি (নীল-হলুদ)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"রঙ সংশোধন"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"আপনার ডিভাইসে রঙগুলি কেমন দেখাবে তা অ্যাডজাস্ট করুন। যেক্ষেত্রে এটি আপনাকে সহায়তা করতে পারে:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; আরও নির্ভুলভাবে রঙ দেখতে&lt;/li&gt; &lt;li&gt; রঙ সরিয়ে দিলে ফোকাস করতে সহায়তা করবে&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"আপনার ডিভাইসে রঙগুলি কেমন দেখাবে তা অ্যাডজাস্ট করুন। যেক্ষেত্রে এটি আপনাকে সহায়তা করতে পারে:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;আরও নির্ভুলভাবে রঙ দেখতে&lt;/li&gt; &lt;li&gt;&amp;nbsp;রঙ সরিয়ে দিয়ে ফোকাস করতে সহায়তা করবে&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> এর দ্বারা ওভাররাইড করা হয়েছে"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"আর আনুমানিক <xliff:g id="TIME_REMAINING">%1$s</xliff:g> চলবে"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index e4bc5a1..08c31ba 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalija (crveno-zeleno)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalija (plavo-žuto)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Ispravka boje"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Podešavanje načina na koji se boje prikazuju na uređaju. To može biti korisno kada želite:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; tačnije prikazati boje&lt;/li&gt; &lt;li&gt; ukloniti boje da se lakše fokusirate&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Podešavanje načina na koji se boje prikazuju na uređaju. To može biti korisno kada želite:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;preciznije prikazati boje&lt;/li&gt; &lt;li&gt;&amp;nbsp;ukloniti boje da se lakše fokusirate&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Zamjenjuje <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Preostalo je još oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index fa441a2..13a90c3 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (vermell-verd)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (blau-groc)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correcció de color"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Ajusta com es mostren els colors al teu dispositiu. Això pot ser útil quan vulguis:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Veure els colors amb més claredat.&lt;/li&gt; &lt;li&gt; Suprimir colors per poder enfocar més fàcilment.&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Ajusta com es mostren els colors al teu dispositiu. Això pot ser útil quan vulguis:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Veure els colors amb més claredat.&lt;/li&gt; &lt;li&gt;&amp;nbsp;Suprimir colors per poder concentrar-te.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"S\'ha substituït per <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>: <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Temps restant aproximat: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 717b681..8598ecc 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomálie (červená a zelená)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomálie (modrá a žlutá)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korekce barev"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Upravte zobrazování barev na svém zařízení. To se může hodit, když chcete:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Aby se barvy zobrazovaly přesněji&lt;/li&gt; &lt;li&gt; Odstranit barvy, abyste se mohli lépe soustředit&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Upravte zobrazování barev na svém zařízení. To se může hodit, když chcete:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Zobrazovat barvy přesněji&lt;/li&gt; &lt;li&gt;&amp;nbsp;Odstranit barvy, abyste se mohli lépe soustředit&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Přepsáno nastavením <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Zbývá asi <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 6b17db1..d17924f 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanopi (rød-grøn)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanopi (blå-gul)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korriger farver"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Juster, hvordan farverne vises på skærmen. Dette kan være nyttigt, når du vil:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Se farver mere nøjagtigt&lt;/li&gt; &lt;li&gt; Fjerne farver, så du bedre kan fokusere&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Juster, hvordan farverne vises på din enhed. Dette kan være nyttigt, når du vil:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Se farver mere nøjagtigt&lt;/li&gt; &lt;li&gt;&amp;nbsp;Fjerne farver, så du bedre kan fokusere&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Tilsidesat af <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Ca. <xliff:g id="TIME_REMAINING">%1$s</xliff:g> tilbage"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index bb11ed1..a0bf4b1 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (Rot-Grün-Sehschwäche)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (Blau-Gelb-Sehschwäche)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Farbkorrektur"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Hier kannst du anpassen, wie Farben auf deinem Gerät dargestellt werden sollen. Das kann in folgenden Fällen hilfreich sein:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Wenn Farben genauer dargestellt werden sollen&lt;/li&gt; &lt;li&gt; Wenn du Farben entfernen möchtest, um dich besser konzentrieren zu können&lt;/li&gt; &lt;/ol&gt;"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (2333641630205214702) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Außer Kraft gesetzt von \"<xliff:g id="TITLE">%1$s</xliff:g>\""</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Noch etwa <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 76faa4c..5e4d52e 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Πρωτανοπία (κόκκινο-πράσινο)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Τριτανοπία (μπλε-κίτρινο)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Διόρθωση χρωμάτων"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Προσαρμόστε πώς θα εμφανίζονται τα χρώματα στη συσκευή σας. Αυτό μπορεί να είναι χρήσιμο όταν θέλετε:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Να βλέπετε τα χρώματα με μεγαλύτερη ακρίβεια&lt;/li&gt; &lt;li&gt; Να καταργήσετε τα χρώματα για να συγκεντρωθείτε&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Προσαρμόστε πώς θα εμφανίζονται τα χρώματα στη συσκευή σας. Αυτό μπορεί να είναι χρήσιμο όταν θέλετε:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Να βλέπετε τα χρώματα με μεγαλύτερη ακρίβεια&lt;/li&gt; &lt;li&gt;&amp;nbsp;Να καταργήσετε τα χρώματα για να συγκεντρωθείτε&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Αντικαταστάθηκε από <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Απομένει/ουν περίπου <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 9a63404..8dfcb40 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (red-green)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (blue-yellow)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Colour correction"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Adjust how colours display on your device. This can be helpful when you want to:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; See colours more accurately&lt;/li&gt; &lt;li&gt; Remove colours to help you focus&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Adjust how colours display on your device. This can be helpful when you want to:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;See colours more accurately&lt;/li&gt; &lt;li&gt;&amp;nbsp;Remove colours to help you focus&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 49271db..17c7934 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (red-green)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (blue-yellow)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Colour correction"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Adjust how colours display on your device. This can be helpful when you want to:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; See colours more accurately&lt;/li&gt; &lt;li&gt; Remove colours to help you focus&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Adjust how colours display on your device. This can be helpful when you want to:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;See colours more accurately&lt;/li&gt; &lt;li&gt;&amp;nbsp;Remove colours to help you focus&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 9a63404..8dfcb40 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (red-green)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (blue-yellow)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Colour correction"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Adjust how colours display on your device. This can be helpful when you want to:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; See colours more accurately&lt;/li&gt; &lt;li&gt; Remove colours to help you focus&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Adjust how colours display on your device. This can be helpful when you want to:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;See colours more accurately&lt;/li&gt; &lt;li&gt;&amp;nbsp;Remove colours to help you focus&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 9a63404..8dfcb40 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (red-green)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (blue-yellow)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Colour correction"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Adjust how colours display on your device. This can be helpful when you want to:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; See colours more accurately&lt;/li&gt; &lt;li&gt; Remove colours to help you focus&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Adjust how colours display on your device. This can be helpful when you want to:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;See colours more accurately&lt;/li&gt; &lt;li&gt;&amp;nbsp;Remove colours to help you focus&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 3476b97..2e7e628 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‏‎‎‏‏‎‎‎‎‎‎‎‎‏‎‏‎‏‎‎‏‎‏‏‎‎‎‏‎‏‎‎‏‎‏‎‏‎‎‎‎‎‏‏‏‎‎‏‏‏‎‎‎‎Protanomaly (red-green)‎‏‎‎‏‎"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‎‎‎‏‎‏‏‎‎‎‏‏‏‎‏‏‎‏‏‎‎‏‎‏‏‏‎‎‏‎‏‎‏‎‎‎‏‎‏‎‏‏‎‏‎‏‎‏‏‎‏‎‏‏‎Tritanomaly (blue-yellow)‎‏‎‎‏‎"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‎‎‏‎‎‏‎‎‎‎‎‏‏‏‎‎‎‎‎‎‎‏‏‎‏‎‏‏‎‏‎‏‏‎‎‎‏‎‏‏‎‎‏‏‎‎‏‏‏‎‏‎‎‎‏‎‏‏‎‎Color correction‎‏‎‎‏‎"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‎‏‏‏‏‏‎‏‎‏‎‏‏‎‎‎‎‎‎‎‎‏‏‎‏‎‎‏‎‎‎‏‎‎‏‏‎‏‎‏‏‎‏‎‎Adjust how colors display on your device. This can be helpful when you want to:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; See colors more accurately&lt;/li&gt; &lt;li&gt; Remove colors to help you focus&lt;/li&gt; &lt;/ol&gt;‎‏‎‎‏‎"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‎‎‎‏‏‎‎‎‏‎‏‏‎‎‎‎‏‎‏‎‏‏‎‎‏‎‏‏‎‏‎‎‎‏‎‏‏‏‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎Adjust how colors display on your device. This can be helpful when you want to:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;See colors more accurately&lt;/li&gt; &lt;li&gt;&amp;nbsp;Remove colors to help you focus&lt;/li&gt; &lt;/ol&gt;‎‏‎‎‏‎"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‏‏‎‏‎‎‏‎‏‎‏‎‏‎‏‎‏‎‏‏‎‏‎‎‎‎‏‎‏‏‎‏‏‎‎‎‎‎‏‎‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‎Overridden by ‎‏‎‎‏‏‎<xliff:g id="TITLE">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‏‏‏‎‎‏‏‎‎‎‎‏‏‎‎‏‏‏‎‎‎‏‏‏‎‎‏‏‎‎‏‎‎‏‏‎‎‏‏‎‏‎‎‎‎‏‏‏‎‏‎‎‏‎‎‏‏‎<xliff:g id="PERCENTAGE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ - ‎‏‎‎‏‏‎<xliff:g id="TIME_STRING">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‎‎‎‎‏‎‏‎‏‎‏‎‏‎‏‏‎‎‏‎‏‏‎‎‏‎‏‏‎‏‏‎‎‏‎‏‏‎‏‏‏‎‏‏‎‏‎‎‏‏‏‎About ‎‏‎‎‏‏‎<xliff:g id="TIME_REMAINING">%1$s</xliff:g>‎‏‎‎‏‏‏‎ left‎‏‎‎‏‎"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index fb294c8..d4f2162 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalía (rojo-verde)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalía (azul-amarillo)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Corrección de color"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Ajusta cómo se muestran los colores en tu dispositivo. Esto puede ser útil cuando quieres:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Ver colores con más exactitud&lt;/li&gt; &lt;li&gt; Quitar colores para mejorar tu concentración&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Ajusta cómo se muestran los colores en tu dispositivo. Esto puede ser útil cuando quieres:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Ver colores con más exactitud&lt;/li&gt; &lt;li&gt; Quitar colores para tener un enfoque más claro&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Reemplazado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tiempo restante: aproximadamente <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 2c5eff2..1a1e84c 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalía (rojo-verde)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalía (azul-amarillo)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Corrección de color"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Ajusta el modo en que se muestran los colores en tu dispositivo. Esto puede ser útil cuando quieras hacer lo siguiente:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Ver los colores con más precisión&lt;/li&gt; &lt;li&gt; Eliminar colores para ayudarte a mantener la concentración&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Ajusta el modo en que se muestran los colores en tu dispositivo. Esto puede ser útil cuando quieras hacer lo siguiente:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Ver los colores con más precisión&lt;/li&gt; &lt;li&gt;&amp;nbsp;Quitar colores para ayudarte a mantener la concentración&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Anulado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>: <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tiempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 116faad..34e3138 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaalia (punane-roheline)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaalia (sinine-kollane)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Värvide korrigeerimine"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Kohandage seadmes värvide kuvamist. Sellest võib olla kasu, kui soovite:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; värve täpsemalt näha;&lt;/li&gt; &lt;li&gt; värve eemaldada, et paremini keskenduda.&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Kohandage seadmes värvide kuvamist. Sellest võib olla kasu, kui soovite:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;värve täpsemalt näha;&lt;/li&gt; &lt;li&gt;&amp;nbsp;värve eemaldada, et paremini keskenduda.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Alistas <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Ligikaudu <xliff:g id="TIME_REMAINING">%1$s</xliff:g> jäänud"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index bfb4efc..a18c0f1 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanopia (gorri-berdeak)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanopia (urdin-horia)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Koloreen zuzenketa"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Doitu nola bistaratzen diren koloreak gailuan. Kasu hauetan izan daiteke lagungarria:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Koloreak zehatzago ikusi nahi dituzunean.&lt;/li&gt; &lt;li&gt; Hobeto fokuratzeko, koloreak kendu nahi dituzunean.&lt;/li&gt; &lt;/ol&gt;"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (2333641630205214702) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> hobespena gainjarri zaio"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> inguru gelditzen dira"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index f3018ba..6b55e89 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"قرمزدشواربینی (قرمز-سبز)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"آبی‌دشواربینی (آبی-زرد)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"تصحیح رنگ"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"‏نحوه نمایش رنگ‌ها را در دستگاهتان تنظیم می‌کند. این ویژگی می‌تواند در موارد زیر مفید باشد:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; وقتی می‌خواهید رنگ‌ها را با دقت بیشتری ببینید&lt;/li&gt; &lt;li&gt; وقتی می‌خواهید رنگ‌ها را حذف کنید تا تمرکز بیشتری داشته باشید"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"‏نحوه نمایش رنگ‌ها را در دستگاهتان تنظیم می‌کند. این ویژگی می‌تواند در موارد زیر مفید باشد:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp; وقتی می‌خواهید رنگ‌ها را با دقت بیشتری ببینید&lt;/li&gt; &lt;li&gt;&amp;nbsp;وقتی می‌خواهید رنگ‌ها را حذف کنید تا تمرکز بیشتری داشته باشید&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"توسط <xliff:g id="TITLE">%1$s</xliff:g> لغو شد"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"تقریباً <xliff:g id="TIME_REMAINING">%1$s</xliff:g> شارژ باقی مانده است"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 7089937..b0519bb 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (puna-vihersokeus)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (sini-keltasokeus)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Värinkorjaus"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Muuta värien näkymistä laitteellasi. Tästä voi olla hyötyä, kun haluat&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; nähdä värit tarkemmin&lt;/li&gt; &lt;li&gt; poistaa värejä voidaksesi keskittyä paremmin&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Muuta värien näkymistä laitteellasi. Tästä voi olla hyötyä, kun haluat&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;nähdä värit tarkemmin&lt;/li&gt; &lt;li&gt;&amp;nbsp;poistaa värejä voidaksesi keskittyä paremmin&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Tämän ohittaa <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Noin <xliff:g id="TIME_REMAINING">%1$s</xliff:g> jäljellä"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index ac8adde..513b7d2 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (rouge/vert)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (bleu/jaune)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correction des couleurs"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Ajustez l\'affichage des couleurs sur votre appareil. Ce paramètre peut être utile si vous voulez :&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Mieux distinguer les couleurs&lt;/li&gt; &lt;li&gt; Enlever les couleurs pour vous aider à vous concentrer&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Ajustez l\'affichage des couleurs sur votre appareil. Ce paramètre peut être utile si vous voulez :&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Mieux distinguer les couleurs&lt;/li&gt; &lt;li&gt;&amp;nbsp;Enlever les couleurs pour vous aider à vous concentrer&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Remplacé par <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> : <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Il reste environ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index e4e4293..fc788b6 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (rouge/vert)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (bleu-jaune)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correction des couleurs"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Ajustez l\'affichage des couleurs sur votre appareil. Cette option peut vous être utile pour :&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; accentuer la précision des couleurs ;&lt;/li&gt; &lt;li&gt; supprimer les couleurs pour mieux vous concentrer.&lt;/li&gt; &lt;/ol&gt;"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (2333641630205214702) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Remplacé par <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Temps restant : environ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 062b7b3..521251f 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalía (vermello-verde)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalía (azul-amarelo)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Corrección da cor"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Axusta a maneira en que se mostran as cores no teu dispositivo. Esta opción pode resultarche útil se queres:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Ver mellor as cores&lt;/li&gt; &lt;li&gt; Quitar as cores para concentrarte mellor&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Axusta a maneira en que se mostran as cores no teu dispositivo. Esta opción pode resultarche útil se queres:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Ver mellor as cores&lt;/li&gt; &lt;li&gt;&amp;nbsp;Quitar as cores para concentrarte mellor&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Anulado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 174d0a1..dd0e452 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"પ્રોટેનોમલી (લાલ-લીલો)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ટ્રાઇટેનોમલી(વાદળી-પીળો)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"રંગ સુધારણા"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"તમારા ડિવાઇસ પર રંગો કેવી રીતે બતાવવામાં આવે તેની ગોઠવણી કરો. આ ત્યારે સહાયરૂપ થઈ શકે છે જ્યારે તમારે:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; રંગો વધુ યોગ્ય રીતે જોવા હોય&lt;/li&gt; &lt;li&gt; તમને ફોકસ કરવામાં સહાયતા રહે તે માટે રંગો કાઢી નાખવા હોય&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"તમારા ડિવાઇસ પર રંગો કેવી રીતે બતાવવામાં આવે તેની ગોઠવણી કરો. આ ત્યારે સહાયરૂપ થઈ શકે છે જ્યારે તમારે:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;રંગો વધુ યોગ્ય રીતે જોવા હોય&lt;/li&gt; &lt;li&gt;&amp;nbsp;તમને ફોકસ કરવામાં સહાયતા રહે તે માટે રંગો કાઢી નાખવા હોય&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> દ્વારા ઓવરરાઇડ થયું"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"લગભગ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> બાકી છે"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 835e760..4e6ccbb 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"लाल रंग पहचान न पाना (लाल-हरा)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"नीला रंग पहचान न पाना (नीला-पीला)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"रंग में सुधार करने की सुविधा"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"आपके डिवाइस पर रंगों के दिखने के तरीके में बदलाव करें. इससे, आपको इनमें मदद मिलेगी:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; रंगों को बेहतर तरीके से देखने में&lt;/li&gt; &lt;li&gt; आसानी से फ़ोकस करने के लिए, रंग हटाने में&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"आपके डिवाइस पर रंगों के दिखने के तरीके में बदलाव करें. इससे, आपको इन कामों में मदद मिलेगी:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;रंगों को बेहतर तरीके से देखने में&lt;/li&gt; &lt;li&gt;&amp;nbsp;आसानी से फ़ोकस के लिए, रंग हटाने में&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> के द्वारा ओवरराइड किया गया"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"बैटरी करीब <xliff:g id="TIME_REMAINING">%1$s</xliff:g> में खत्म हो जाएगी"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 3d06baa..0f2c684 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalija (crveno – zeleno)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalija (plavo – žuto)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korekcija boje"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Prilagodite način prikazivanja boja na svojem uređaju. To može biti korisno kad želite:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; vidjeti boje točnije&lt;/li&gt; &lt;li&gt; ukloniti boje kako biste se lakše usredotočili&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Prilagodite način prikazivanja boja na svojem uređaju. To može biti korisno kad želite:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;vidjeti boje točnije&lt;/li&gt; &lt;li&gt;&amp;nbsp;ukloniti boje kako biste se lakše usredotočili.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Premošćeno postavkom <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Još otprilike <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 546a038..fd24084 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomália (piros– zöld)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomália (kék–sárga)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Színkorrekció"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Korrigálhatja a színek megjelenítését az eszközén. Ez a következő esetekben lehet hasznos:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; ha pontosabb színeket szeretne látni;&lt;/li&gt; &lt;li&gt; ha szeretné eltávolítani a színeket, hogy jobban tudjon koncentrálni.&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Korrigálhatja a színek megjelenítését az eszközén. Ez a következő esetekben lehet hasznos:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;ha pontosabb színeket szeretne látni;&lt;/li&gt; &lt;li&gt;&amp;nbsp;ha szeretné eltávolítani a színeket, hogy jobban tudjon koncentrálni.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Felülírva erre: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Körülbelül <xliff:g id="TIME_REMAINING">%1$s</xliff:g> maradt hátra"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 7c0963d..1201b10 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Պրոտանոմալիա (կարմիր-կանաչ)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Տրիտանոմալիա (կապույտ-դեղին)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Գունաշտկում"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Կարգավորեք գույների ցուցադրումը ձեր սարքում։ Դա կարող է օգտակար լինել, երբ դուք ուզում եք՝&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Ավելի հստակ տեսնել գույները&lt;/li&gt; &lt;li&gt; Հեռացնել գույները՝ կենտրոնանալու համար&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Կարգավորեք գույների ցուցադրումը ձեր սարքում։ Դա կարող է օգտակար լինել, երբ դուք ուզում եք՝&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Ավելի հստակ տեսնել գույները&lt;/li&gt; &lt;li&gt;&amp;nbsp;Հեռացնել գույները՝ կենտրոնանալու համար&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Գերազանցված է <xliff:g id="TITLE">%1$s</xliff:g>-ից"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Լիցքը կբավարարի մոտ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 2f8bb46..3c658ad 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomali (merah-hijau)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomali (biru-kuning)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Koreksi warna"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Sesuaikan cara warna ditampilkan di perangkat Anda. Ini dapat bermanfaat saat Anda ingin:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Melihat warna dengan lebih akurat&lt;/li&gt; &lt;li&gt; Menghapus warna untuk membantu Anda fokus&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Sesuaikan cara warna ditampilkan di perangkat Anda. Ini dapat bermanfaat saat Anda ingin:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Melihat warna dengan lebih akurat&lt;/li&gt; &lt;li&gt;&amp;nbsp;Menghapus warna untuk membantu Anda fokus&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Digantikan oleh <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Sekitar <xliff:g id="TIME_REMAINING">%1$s</xliff:g> lagi"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index ea29258..b36adc8 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Litblinda (rauðgræn)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Litblinda (blágul)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Litaleiðrétting"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Stilltu litabirtingu í tækinu þínu. Þetta getur gagnast þegar þú vilt:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Sjá liti skýrar&lt;/li&gt; &lt;li&gt; Fjarlægja liti til að fókusa betur&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Stilltu litabirtingu í tækinu þínu. Þetta getur gagnast þegar þú vilt:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Sjá liti skýrar&lt;/li&gt; &lt;li&gt;&amp;nbsp;Fjarlægja liti til að fókusa betur&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Hnekkt af <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Um það bil <xliff:g id="TIME_REMAINING">%1$s</xliff:g> eftir"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 5dd7a52..31e9d36 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalìa (rosso-verde)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalìa (blu-giallo)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correzione del colore"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Regola la modalità di visualizzazione dei colori sul tuo dispositivo. Può essere utile se vuoi:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Vedere i colori con più precisione&lt;/li&gt; &lt;li&gt; Rimuovere colori per mettere a fuoco più facilmente&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Regola la modalità di visualizzazione dei colori sul tuo dispositivo. Può essere utile se vuoi:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Vedere i colori con più precisione&lt;/li&gt; &lt;li&gt;&amp;nbsp;Rimuovere colori per mettere a fuoco più facilmente&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Valore sostituito da <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tempo rimanente: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> circa"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 20d1e1b..90df3b1 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"פרוטנומליה (אדום-ירוק)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"טריטנומליה (כחול-צהוב)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"תיקון צבע"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"‏ניתן לשנות את האופן שבו צבעים מוצגים במכשיר. שינוי כזה עשוי לעזור:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; להבחין בצבעים בצורה יותר מדויקת&lt;/li&gt; &lt;li&gt; להסיר צבעים מסוימים כדי להתמקד&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"‏ניתן לשנות את האופן שבו צבעים מוצגים במכשיר. שינוי כזה עשוי לעזור:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; להבחין בצבעים בצורה יותר מדויקת&lt;/li&gt; &lt;li&gt; להסיר צבעים מסוימים כדי להתמקד&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"נעקף על ידי <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"הזמן הנותר: בערך <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 4a9126f..9421991 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"第一色弱(赤緑)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"第三色弱(青黄)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"色補正"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"デバイスで色をどのように表示するかを調整できます。この設定は以下の場合に役立ちます。&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; 色をより正確に表示したい場合&lt;/li&gt; &lt;li&gt; はっきり読み取れるよう色を取り除きたい場合&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"デバイスで色をどのように表示するかを調整できます。この設定は以下の場合に役立ちます。&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;色をより正確に表示したい場合&lt;/li&gt; &lt;li&gt;&amp;nbsp;はっきり読み取れるよう色を取り除きたい場合&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g>によって上書き済み"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"残り時間: 約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 37db15c..9371a1a 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"პროტოანომალია (წითელი-მწვანე)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ტრიტანომალია (ლურჯი-ყვითელი)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ფერის კორექცია"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"დააკორექტირეთ, როგორ გამოჩნდება ფერები თქვენს მოწყობილობაზე. ეს შეიძლება დაგეხმაროთ, როდესაც გსურთ:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; ფერების მეტი სიზუსტით დანახვა&lt;/li&gt; &lt;li&gt; ფერების მოცილება, რომ უკეთ კონცენტრირდეთ&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"დააკორექტირეთ, როგორ გამოჩნდება ფერები თქვენს მოწყობილობაზე. ეს შეიძლება დაგეხმაროთ, როდესაც გსურთ:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;ფერების მეტი სიზუსტით დანახვა&lt;/li&gt; &lt;li&gt;&amp;nbsp;ფერების მოცილება, რომ უკეთ კონცენტრირდეთ&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"უკუგებულია <xliff:g id="TITLE">%1$s</xliff:g>-ის მიერ"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"დარჩა დაახლოებით <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 878966d..22f6001 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалия (қызыл-жасыл)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалия (көк-сары)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Түсті түзету"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Құрылғыңызда түстер қалай көрсетілетінін реттеңіз. Бұл мыналар үшін пайдалы болуы мүмкін:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; түстерді анығырақ көру&lt;/li&gt; &lt;li&gt; зейініңізді жақсарту үшін түстерді өшіру&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Құрылғыңызда түстердің қалай көрсетілетінін реттеңіз. Бұл мыналар үшін пайдалы болуы мүмкін:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;түстерді анығырақ көру&lt;/li&gt; &lt;li&gt;&amp;nbsp;зейініңізді жақсарту үшін түстерді өшіру&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> үстінен басқан"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Шамамен <xliff:g id="TIME_REMAINING">%1$s</xliff:g> қалды"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 708879a..cace862 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (ក្រហម​ពណ៌​បៃតង​)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (ពណ៌​ខៀវ​-លឿង​)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ការ​កែ​ពណ៌"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"កែតម្រូវ​របៀបដែលពណ៌​បង្ហាញនៅលើ​ឧបករណ៍​របស់អ្នក។ ចំណុចនេះ​អាចមានប្រយោជន៍ នៅពេលដែល​អ្នកចង់៖&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; មើលឃើញពណ៌​កាន់តែត្រឹមត្រូវ&lt;/li&gt; &lt;li&gt; លុបពណ៌ ដើម្បីជួយអ្នក​ក្នុងការផ្ដោត&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"កែតម្រូវ​របៀបដែលពណ៌​បង្ហាញនៅលើ​ឧបករណ៍​របស់អ្នក។ ចំណុចនេះ​អាចមានប្រយោជន៍ នៅពេលដែល​អ្នកចង់៖&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;មើលឃើញពណ៌​កាន់តែត្រឹមត្រូវ&lt;/li&gt; &lt;li&gt;&amp;nbsp;លុបពណ៌ ដើម្បីជួយអ្នក​ក្នុងការផ្ដោតអារម្មណ៍&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"បដិសេធ​ដោយ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"នៅសល់​ប្រហែល <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ទៀត"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index daf7b6f..e2b62a4 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"ಪ್ರೊಟನೋಮಲಿ (ಕೆಂಪು-ಹಸಿರು)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ಟ್ರಿಟನೋಮಲಿ (ನೀಲಿ-ಹಳದಿ)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ಬಣ್ಣದ ತಿದ್ದುಪಡಿ"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಬಣ್ಣಗಳು ಹೇಗೆ ಡಿಸ್‌ಪ್ಲೇ ಆಗುತ್ತವೆ ಎಂಬುದನ್ನು ಹೊಂದಿಸಿ. ನೀವು ಬಣ್ಣಗಳನ್ನು ಹೆಚ್ಚು ನಿಖರವಾಗಿ ನೋಡಲು ಬಯಸಿದಾಗ:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; ಇದು ಸಹಾಯಕವಾಗಿರುತ್ತದೆ&lt;/li&gt; &lt;li&gt; ನಿಮಗೆ ಗಮನಹರಿಸಲು ಸಹಾಯ ಮಾಡಲು ಬಣ್ಣಗಳನ್ನು ತೆಗೆದುಹಾಕಿ&lt;/li&gt; &lt;/ol&gt;"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (2333641630205214702) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ಮೂಲಕ ಅತಿಕ್ರಮಿಸುತ್ತದೆ"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ಸಮಯ ಬಾಕಿ ಉಳಿದಿದೆ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index c9960c4..7d49dd9 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"적색약(적녹)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"청색약(청황)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"색상 보정"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"기기에 색상이 표시되는 방식을 조정합니다. 색상을 더 정확하게 보고 싶거나 집중을 위해 일부 색상을 제거할 때 유용합니다."</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"기기에 색상이 표시되는 방식을 조정합니다. 다음과 같은 상황에서 유용합니다.&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;색상을 더욱 정확하게 보고 싶을 때&lt;/li&gt; &lt;li&gt;&amp;nbsp;집중을 위해 색상을 제거하고 싶을 때&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> 우선 적용됨"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>, <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"남은 시간 약 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 834200d..1120fe3 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалия (кызыл-жашыл)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалия (көк-сары)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Түсүн тууралоо"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Түзмөгүңүздө түстөр кантип көрүнөрүн тууралаңыз. Бул төмөнкү учурларда пайдалуу болот:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Түстөрдү даана көрүү&lt;/li&gt; &lt;li&gt; Ынтаа коюу үчүн түстөрдү өчүрүү&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Түзмөгүңүздө түстөр кантип көрүнөрүн тууралаңыз. Бул төмөнкү учурларда пайдалуу болот:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Түстөрдү даана көрүү&lt;/li&gt; &lt;li&gt;&amp;nbsp;Ынтаа коюу үчүн түстөрдү өчүрүү&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> менен алмаштырылган"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Болжол менен <xliff:g id="TIME_REMAINING">%1$s</xliff:g> калды"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 0dcf1627..043dd99 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (ສີ​ແດງ​-ສີ​ຂຽວ​)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (ສີ​ຟ້າ​-ສີ​ເຫຼືອງ​)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ການ​ປັບ​ແຕ່ງ​ສີ"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"ປັບແກ້ການສະແດງສີຢູ່ອຸປະກອນຂອງທ່ານ. ນີ້ອາດມີປະໂຫຍດໃນເວລາທີ່ທ່ານຕ້ອງການ:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; ເບິ່ງເຫັນສີໄດ້ຖືກຕ້ອງຍິ່ງຂຶ້ນ&lt;/li&gt; &lt;li&gt; ລຶບສີອອກເພື່ອຊ່ວຍໃຫ້ທ່ານມີສະມາທິ&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"ປັບແກ້ການສະແດງສີຢູ່ອຸປະກອນຂອງທ່ານ. ນີ້ອາດມີປະໂຫຍດໃນເວລາທີ່ທ່ານຕ້ອງການ:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;ເບິ່ງເຫັນສີໄດ້ຖືກຕ້ອງຍິ່ງຂຶ້ນ&lt;/li&gt; &lt;li&gt;&amp;nbsp;ລຶບສີອອກເພື່ອຊ່ວຍໃຫ້ທ່ານມີສະມາທິ&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"ຖືກແທນໂດຍ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"ເຫຼືອອີກປະມານ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index c3f9202..e31da9e 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalija (raudona, žalia)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalija (mėlyna, geltona)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Spalvų taisymas"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Koreguokite, kaip spalvos rodomos jūsų įrenginyje. Tai gali būti naudinga, kai norite:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; matyti tikslesnes spalvas;&lt;/li&gt; &lt;li&gt; pašalinti spalvas, kad būtų lengviau susitelkti.&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Koreguokite, kaip spalvos rodomos jūsų įrenginyje. Tai gali būti naudinga, kai norite:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;matyti tikslesnes spalvas;&lt;/li&gt; &lt;li&gt;&amp;nbsp;pašalinti spalvas, kad būtų lengviau susitelkti.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Nepaisyta naudojant nuostatą „<xliff:g id="TITLE">%1$s</xliff:g>“"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Liko maždaug <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 5090df0..aa747be 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomālija (sarkans/zaļš)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomālija (zils/dzeltens)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Krāsu korekcija"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Pielāgojiet krāsu attēlojumu jūsu ierīcē. Izmantojiet šo funkciju, lai:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; skatītu precīzāku krāsu attēlojumu;&lt;/li&gt; &lt;li&gt; noņemtu krāsas, kad jāpievēršas kādam uzdevumam.&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Pielāgojiet krāsu attēlojumu savā ierīcē. Izmantojot šo iestatījumu, varat:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;skatīt precīzāku krāsu attēlojumu;&lt;/li&gt; &lt;li&gt;&amp;nbsp;noņemt krāsas, lai būtu vieglāk koncentrēties.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Jaunā preference: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> — <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Aptuvenais atlikušais laiks: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index c4890d4..fc22362 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалија (слепило за црвена и зелена)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалија (слепило за сина и жолта)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Корекција на бои"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Приспособете го приказот на боите на уредот. Ова е корисно кога сакате:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; да гледате попрецизни бои&lt;/li&gt; &lt;li&gt; да отстраните бои за подобра концентрација&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Приспособете го приказот на боите на уредот. Ова е корисно кога сакате:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;да гледате попрецизни бои&lt;/li&gt; &lt;li&gt;&amp;nbsp;да отстраните бои за подобра концентрација&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Прескокнато според <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Уште околу <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 829d474..15b91df 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"പ്രോട്ടാനോമലി (ചുവപ്പ്-പച്ച)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ട്രിട്ടാനോമലി (നീല-മഞ്ഞ)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"നിറം ക്രമീകരിക്കൽ"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"നിങ്ങളുടെ ഉപകരണത്തിൽ നിറങ്ങൾ എങ്ങനെ പ്രദർശിപ്പിക്കണമെന്ന് ക്രമീകരിക്കുക. ഇനിപ്പറയുന്ന കാര്യങ്ങൾ ചെയ്യാൻ ആഗ്രഹിക്കുമ്പോൾ ഇത് സഹായകരമാകും:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; നിറങ്ങൾ കൂടുതൽ കൃത്യമായി കാണാൻ&lt;/li&gt; &lt;li&gt; ഫോക്കസ് ചെയ്യാൻ നിങ്ങളെ സഹായിക്കുന്നതിന് നിറങ്ങൾ നീക്കം ചെയ്യാൻ&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"നിങ്ങളുടെ ഉപകരണത്തിൽ നിറങ്ങൾ എങ്ങനെ പ്രദർശിപ്പിക്കണമെന്ന് ക്രമീകരിക്കുക. ഇനിപ്പറയുന്ന കാര്യങ്ങൾ ചെയ്യാൻ ആഗ്രഹിക്കുമ്പോൾ ഇത് സഹായകരമാകും:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;നിറങ്ങൾ കൂടുതൽ കൃത്യമായി കാണാൻ&lt;/li&gt; &lt;li&gt;&amp;nbsp;ഫോക്കസ് ചെയ്യാൻ നിങ്ങളെ സഹായിക്കുന്നതിന് നിറങ്ങൾ നീക്കം ചെയ്യാൻ&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ഉപയോഗിച്ച് അസാധുവാക്കി"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"ഏതാണ്ട് <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ശേഷിക്കുന്നു"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 7c833f7..2d2289e 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномаль (улаан-ногоон)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомаль (цэнхэр-шар)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Өнгө тохируулах"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Таны төхөөрөмж дээр өнгийг хэрхэн үзүүлэхийг тохируулна уу. Энэ нь таныг дараахыг хийхийг хүссэн үед хэрэгтэй байж болно:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Өнгийг илүү оновчтой харах&lt;/li&gt; &lt;li&gt; Төвлөрөхийн тулд өнгийг хасах&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Таны төхөөрөмж дээр өнгийг хэрхэн үзүүлэхийг тохируулна уу. Энэ нь танд дараахыг хийхийг хүссэн үед хэрэг болж магадгүй:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;Өнгийг илүү оновчтой харах&lt;/li&gt; &lt;li&gt;Танд төвлөрөхөд туслахын тулд өнгийг хасах&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Давхарласан <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Ойролцоогоор <xliff:g id="TIME_REMAINING">%1$s</xliff:g> үлдсэн"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index e9fe1dd..979a685 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"क्षीण रक्तवर्णांधता (लाल-हिरवा)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"रंग दृष्टी कमतरता (निळा-पिवळा)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"रंग सुधारणा"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"तुमच्या डिव्हाइसवर रंग कसे प्रदर्शित केले जातात ते अ‍ॅडजस्ट करा. तुम्हाला &lt;/br&gt;&lt;br&gt; &lt;/br&gt;&lt;br&gt; &lt;/br&gt;&lt;br&gt;अधिक स्पष्टपणे रंग पाहणे &lt;/br&gt;&lt;br&gt; &lt;/br&gt;&lt;br&gt; तुम्हाला फोकस करण्यात मदत करण्यासाठी रंग काढून टाकणे&lt;/br&gt;&lt;br&gt; &lt;/br&gt;&lt;br&gt; हे करायचे असते तेव्हा उपयुक्त असू शकते."</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (2333641630205214702) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> द्वारे अधिलिखित"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"अंदाजे <xliff:g id="TIME_REMAINING">%1$s</xliff:g> बाकी आहे"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 4df3855..31ba5af 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomali (merah-hijau)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomali (biru-kuning)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Pembetulan warna"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Laraskan cara warna dipaparkan pada peranti anda. Ini boleh membantu apabila anda ingin:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Lihat warna dengan lebih tepat&lt;/li&gt; &lt;li&gt; Alih keluar warna untuk membantu anda fokus&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Laraskan cara warna dipaparkan pada peranti anda. Ini boleh membantu apabila anda ingin:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Lihat warna dengan lebih tepat&lt;/li&gt; &lt;li&gt;&amp;nbsp;Alih keluar warna untuk membantu anda fokus&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Diatasi oleh <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Kira-kira <xliff:g id="TIME_REMAINING">%1$s</xliff:g> lagi"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index d80242ef..a3fa9c7 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (အနီ-အစိမ်း)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (အပြာ-အဝါ)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"အရောင်ပြင်ဆင်မှု"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"သင့်စက်ပစ္စည်းတွင် အရောင်များပြသပုံကို ချိန်ညှိပါ။ ၎င်းက အောက်ပါတို့တွင် အသုံးဝင်နိုင်သည်-&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; အရောင်များကို ပိုမိုတိကျစွာ မြင်လိုခြင်း&lt;/li&gt; &lt;li&gt; သင်အာရုံစိုက်နိုင်ရန် အရောင်များကို ဖယ်ရှားခြင်း&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"သင့်စက်ပစ္စည်းတွင် အရောင်များပြသပုံကို ချိန်ညှိပါ။ ၎င်းက အောက်ပါတို့တွင် အသုံးဝင်နိုင်သည်-&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;အရောင်များကို ပိုမိုတိကျစွာ မြင်လိုခြင်း&lt;/li&gt; &lt;li&gt;&amp;nbsp;သင်အာရုံစိုက်နိုင်ရန် အရောင်များကို ဖယ်ရှားခြင်း&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> မှ ကျော်၍ လုပ်ထားသည်။"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ခန့် ကျန်သည်"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 7b49b40..42a59cb 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomali (rød-grønn)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomali (blå-gul)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Fargekorrigering"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Juster hvordan farger vises på enheten. Dette kan være nyttig når du vil&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; se farger mer nøyaktig&lt;/li&gt; &lt;li&gt; fjerne farger for å gjøre det enklere å fokusere&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Juster hvordan farger vises på enheten. Dette kan være nyttig når du vil&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;se farger mer nøyaktig&lt;/li&gt; &lt;li&gt;&amp;nbsp;fjerne farger for å gjøre det enklere å fokusere&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overstyres av <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Omtrent <xliff:g id="TIME_REMAINING">%1$s</xliff:g> gjenstår"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 4d380a5..2b351bc 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"प्रोटानेमली (रातो, हरियो)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ट्रिटानोमेली (निलो-पंहेलो)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"रङ्ग सुधार"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"तपाईंको यन्त्रमा रङहरू कस्ता देखिन्छन् भन्ने कुरा मिलाउनुहोस्। यो सुविधा निम्न अवस्थामा उपयोगी हुन सक्छ:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; तपाईं अझ सटीक रूपमा रङहरू देख्न चाहनुहुन्छ भने&lt;/li&gt; &lt;li&gt; तपाईं कुनै कुरामा ध्यान केन्द्रित गर्न रङहरू हटाउन चाहनुहुन्छ भने&lt;/li&gt; &lt;/ol&gt;"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (2333641630205214702) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> द्वारा अधिरोहित"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"लगभग <xliff:g id="TIME_REMAINING">%1$s</xliff:g> बाँकी छ"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 518aaa9..a3a490d 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -236,7 +236,7 @@
     <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Maak verbinding met een wifi-netwerk"</string>
     <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, foutopsporing, ontwikkeling"</string>
     <string name="bugreport_in_power" msgid="8664089072534638709">"Snelle link naar bugrapport"</string>
-    <string name="bugreport_in_power_summary" msgid="1885529649381831775">"Een knop in het aan/uit-menu weergeven om een bugrapport te maken"</string>
+    <string name="bugreport_in_power_summary" msgid="1885529649381831775">"Een knop in het aan/uit-menu tonen om een bugrapport te maken"</string>
     <string name="keep_screen_on" msgid="1187161672348797558">"Stand-by"</string>
     <string name="keep_screen_on_summary" msgid="1510731514101925829">"Scherm gaat nooit uit tijdens het opladen"</string>
     <string name="bt_hci_snoop_log" msgid="7291287955649081448">"Snoop-logbestand voor Bluetooth-HCI inschakelen"</string>
@@ -255,7 +255,7 @@
     <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Via wifi ondersteunde MAC-herschikking"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobiele data altijd actief"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardwareversnelling voor tethering"</string>
-    <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth-apparaten zonder namen weergeven"</string>
+    <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth-apparaten zonder naam tonen"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Absoluut volume uitschakelen"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche inschakelen"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth-AVRCP-versie"</string>
@@ -281,8 +281,8 @@
     <string name="private_dns_mode_provider" msgid="3619040641762557028">"Hostnaam van privé-DNS-provider"</string>
     <string name="private_dns_mode_provider_hostname_hint" msgid="6564868953748514595">"Geef hostnaam van DNS-provider op"</string>
     <string name="private_dns_mode_provider_failure" msgid="8356259467861515108">"Kan geen verbinding maken"</string>
-    <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Opties weergeven voor certificering van draadloze weergave"</string>
-    <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Logniveau voor wifi verhogen, weergeven per SSID RSSI in wifi-kiezer"</string>
+    <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Opties tonen voor certificering van draadloze weergave"</string>
+    <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Logniveau voor wifi verhogen, tonen per SSID RSSI in wifi-kiezer"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Verlaagt het batterijverbruik en verbetert de netwerkprestaties"</string>
     <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Als deze modus is ingeschakeld, kan het MAC-adres van dit apparaat elke keer wijzigen als het verbinding maakt met een netwerk waarvoor MAC-herschikking is ingeschakeld."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Met datalimiet"</string>
@@ -297,7 +297,7 @@
     <string name="select_usb_configuration_dialog_title" msgid="3579567144722589237">"USB-configuratie selecteren"</string>
     <string name="allow_mock_location" msgid="2102650981552527884">"Neplocaties toestaan"</string>
     <string name="allow_mock_location_summary" msgid="179780881081354579">"Neplocaties toestaan"</string>
-    <string name="debug_view_attributes" msgid="3539609843984208216">"Inspectie van weergavekenmerk inschakelen"</string>
+    <string name="debug_view_attributes" msgid="3539609843984208216">"Inspectie van weergavekenmerk aanzetten"</string>
     <string name="mobile_data_always_on_summary" msgid="1112156365594371019">"Mobiele data altijd actief houden, ook als wifi actief is (voor sneller schakelen tussen netwerken)."</string>
     <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Hardwareversnelling voor tethering gebruiken indien beschikbaar"</string>
     <string name="adb_warning_title" msgid="7708653449506485728">"USB-foutopsporing toestaan?"</string>
@@ -334,12 +334,12 @@
     <string name="strict_mode_summary" msgid="1838248687233554654">"Knipperend scherm bij lange bewerkingen door apps"</string>
     <string name="pointer_location" msgid="7516929526199520173">"Cursorlocatie"</string>
     <string name="pointer_location_summary" msgid="957120116989798464">"Schermoverlay met huidige aanraakgegevens"</string>
-    <string name="show_touches" msgid="8437666942161289025">"Tikken weergeven"</string>
-    <string name="show_touches_summary" msgid="3692861665994502193">"Visuele feedback weergeven voor tikken"</string>
-    <string name="show_screen_updates" msgid="2078782895825535494">"Oppervlakupdates weergeven"</string>
+    <string name="show_touches" msgid="8437666942161289025">"Tikken tonen"</string>
+    <string name="show_touches_summary" msgid="3692861665994502193">"Visuele feedback tonen voor tikken"</string>
+    <string name="show_screen_updates" msgid="2078782895825535494">"Oppervlakupdates tonen"</string>
     <string name="show_screen_updates_summary" msgid="2126932969682087406">"Volledige vensteroppervlakken flashen bij updates"</string>
     <string name="show_hw_screen_updates" msgid="2021286231267747506">"Weergave-updates tonen"</string>
-    <string name="show_hw_screen_updates_summary" msgid="3539770072741435691">"Flash-weergave in vensters bij update"</string>
+    <string name="show_hw_screen_updates_summary" msgid="3539770072741435691">"Flash-weergaven in vensters bij update"</string>
     <string name="show_hw_layers_updates" msgid="5268370750002509767">"Hardwarelayer-upd. tonen"</string>
     <string name="show_hw_layers_updates_summary" msgid="5850955890493054618">"Hardwarelagen knipperen groen bij updates"</string>
     <string name="debug_hw_overdraw" msgid="8944851091008756796">"Foutopsporing GPU-overbelasting"</string>
@@ -349,8 +349,8 @@
     <string name="enable_opengl_traces_title" msgid="4638773318659125196">"OpenGL-sporen inschakelen"</string>
     <string name="usb_audio_disable_routing" msgid="3367656923544254975">"USB-audiorouting uitsch."</string>
     <string name="usb_audio_disable_routing_summary" msgid="8768242894849534699">"Autom. routing naar USB-randapparatuur uitsch."</string>
-    <string name="debug_layout" msgid="1659216803043339741">"Indelingsgrenzen weergeven"</string>
-    <string name="debug_layout_summary" msgid="8825829038287321978">"Clipgrenzen, marges en meer weergeven"</string>
+    <string name="debug_layout" msgid="1659216803043339741">"Indelingsgrenzen tonen"</string>
+    <string name="debug_layout_summary" msgid="8825829038287321978">"Clipgrenzen, marges en meer tonen"</string>
     <string name="force_rtl_layout_all_locales" msgid="8690762598501599796">"V.r.n.l.-indelingsrichting afdwingen"</string>
     <string name="force_rtl_layout_all_locales_summary" msgid="6663016859517239880">"Schermindelingsrichting geforceerd instellen op v.r.n.l. voor alle talen"</string>
     <string name="force_msaa" msgid="4081288296137775550">"4x MSAA forceren"</string>
@@ -404,9 +404,9 @@
     <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="transcode_notification" msgid="5560515979793436168">"Transcoderingsmeldingen tonen"</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="runningservices_settings_summary" msgid="1046080643262665743">"Services die momenteel actief zijn, bekijken en beheren"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementatie"</string>
     <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"WebView-implementatie instellen"</string>
     <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Deze keuze is niet meer geldig. Probeer het opnieuw."</string>
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (rood-groen)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (blauw-geel)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Kleurcorrectie"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Aanpassen hoe kleuren worden getoond op je apparaat. In de volgende gevallen kan dit handig zijn:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Je wilt kleuren duidelijker zien.&lt;/li&gt; &lt;li&gt; Je wilt kleuren verwijderen zodat je je beter kunt focussen.&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Aanpassen hoe kleuren worden getoond op je apparaat. In de volgende gevallen kan dit handig zijn:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Je wilt kleuren duidelijker zien.&lt;/li&gt; &lt;li&gt;&amp;nbsp;Je wilt kleuren verwijderen zodat je je beter kunt focussen.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overschreven door <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Nog ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index b0fff21..b7a6819 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"ପ୍ରୋଟାନୋମାଲି (ଲାଲ୍‌-ସବୁଜ)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (ନୀଳ-ହଳଦିଆ)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ରଙ୍ଗ ସଂଶୋଧନ"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"ଆପଣଙ୍କ ଡିଭାଇସରେ ରଙ୍ଗଗୁଡ଼ିକ କିପରି ଡିସପ୍ଲେ ହୁଏ ତାହା ଆଡଜଷ୍ଟ କରନ୍ତୁ। ଆପଣ ଏହା କରିବାକୁ ଚାହିଁଲେ ଏହା ଉପଯୋଗୀ ହୋଇପାରେ:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; ଆହୁରି ସଠିକ୍ ଭାବେ ରଙ୍ଗଗୁଡ଼ିକୁ ଦେଖିବା&lt;/li&gt; &lt;li&gt; ଆପଣଙ୍କୁ ଫୋକସ୍ କରିବାରେ ସାହାଯ୍ୟ କରିବାକୁ ରଙ୍ଗଗୁଡ଼ିକୁ କାଢ଼ିବା&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"ଆପଣଙ୍କ ଡିଭାଇସରେ ରଙ୍ଗଗୁଡ଼ିକ କିପରି ଡିସପ୍ଲେ ହୁଏ ତାହା ଆଡଜଷ୍ଟ କରନ୍ତୁ। ଆପଣ ଏହା କରିବାକୁ ଚାହିଁଲେ ଏହା ଉପଯୋଗୀ ହୋଇପାରେ:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;ଆହୁରି ସଠିକ୍ ଭାବେ ରଙ୍ଗଗୁଡ଼ିକୁ ଦେଖିବା&lt;/li&gt; &lt;li&gt;&amp;nbsp;ଆପଣଙ୍କୁ ଫୋକସ୍ କରିବାରେ ସାହାଯ୍ୟ କରିବାକୁ ରଙ୍ଗଗୁଡ଼ିକୁ କାଢ଼ିବା&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ଦ୍ୱାରା ଓଭର୍‌ରାଇଡ୍‌ କରାଯାଇଛି"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"ପାଖାପାଖି <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ବଳକା ଅଛି"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 71e2dba..f1d4a8a 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (ਲਾਲ-ਹਰਾ)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (ਨੀਲਾ-ਪੀਲਾ)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ਰੰਗ ਸੁਧਾਈ"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"ਆਪਣੇ ਡੀਵਾਈਸ \'ਤੇ ਰੰਗਾਂ ਨੂੰ ਦਿਖਾਉਣ ਦੇ ਤਰੀਕੇ ਨੂੰ ਵਿਵਸਥਿਤ ਕਰੋ। ਇਹ ਉਦੋਂ ਲਾਹੇਵੰਦ ਹੋ ਸਕਦਾ ਹੈ ਜਦੋਂ ਤੁਸੀਂ ਇਹ ਕਰਨਾ ਚਾਹੋਗੇ:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; ਰੰਗਾਂ ਨੂੰ ਹੋਰ ਸਟੀਕਤਾ ਨਾਲ ਦੇਖਣਾ&lt;/li&gt; &lt;li&gt; ਫੋਕਸ ਕਰਨ ਵਿੱਚ ਤੁਹਾਡੀ ਮਦਦ ਲਈ ਰੰਗਾਂ ਨੂੰ ਹਟਾਉਣਾ&lt;/li&gt; &lt;/ol&gt;"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (2333641630205214702) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ਦੁਆਰਾ ਓਵਰਰਾਈਡ ਕੀਤਾ"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"ਲਗਭਗ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ਬਾਕੀ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index c8d7287..cae9f4e 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (czerwony-zielony)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (niebieski-żółty)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korekcja kolorów"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Dostosuj sposób wyświetlania kolorów na ekranie urządzenia. Może to być pomocne, gdy chcesz:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; dokładniej widzieć kolory;,&lt;/li&gt; &lt;li&gt; usunąć wybrane kolory, aby móc skuteczniej się skupić.&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Dostosuj sposób wyświetlania kolorów na ekranie urządzenia. Może to być pomocne, gdy chcesz:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;dokładniej widzieć kolory;&lt;/li&gt; &lt;li&gt;&amp;nbsp;usunąć wybrane kolory, aby móc skuteczniej się skupić.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Nadpisana przez <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Jeszcze około <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 1d6624d..4efdbe2 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (vermelho-verde)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (azul-amarelo)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correção de cor"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Ajuste as cores exibidas no seu dispositivo. Esta opção pode ser útil quando você quer:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; ver cores com mais precisão;&lt;/li&gt; &lt;li&gt; remover cores para se concentrar melhor.&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Ajuste as cores exibidas no seu dispositivo. Essa opção pode ser útil quando você quer:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;ver cores com mais precisão;&lt;/li&gt; &lt;li&gt;&amp;nbsp;remover cores para se concentrar melhor.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 66d4b23..5988a12 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (vermelho-verde)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (azul-amarelo)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correção da cor"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Ajuste a visualização das cores no dispositivo. Isto pode ser útil quando pretender:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Ver cores com maior precisão&lt;/li&gt; &lt;li&gt; Remover cores para melhorar a sua concentração&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Ajuste a visualização das cores no dispositivo. Isto pode ser útil quando pretender:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Ver cores com maior precisão&lt;/li&gt; &lt;li&gt;&amp;nbsp;Remover cores para melhorar a sua concentração&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Resta(m) cerca de <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 1d6624d..4efdbe2 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (vermelho-verde)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (azul-amarelo)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correção de cor"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Ajuste as cores exibidas no seu dispositivo. Esta opção pode ser útil quando você quer:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; ver cores com mais precisão;&lt;/li&gt; &lt;li&gt; remover cores para se concentrar melhor.&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Ajuste as cores exibidas no seu dispositivo. Essa opção pode ser útil quando você quer:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;ver cores com mais precisão;&lt;/li&gt; &lt;li&gt;&amp;nbsp;remover cores para se concentrar melhor.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 3e77ab6..7d2ef6a 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (roșu-verde)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (albastru-galben)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Corecția culorii"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Ajustați modul în care se afișează culorile pe dispozitiv. Acest lucru poate fi util când doriți să:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; vedeți culorile mai bine&lt;/li&gt; &lt;li&gt; eliminați culorile pentru a vă ajuta să vă concentrați&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Ajustați modul în care se afișează culorile pe dispozitiv. Acest lucru poate fi util când doriți să:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;vedeți culorile mai bine;&lt;/li&gt; &lt;li&gt;&amp;nbsp; eliminați culorile pentru a vă ajuta să vă concentrați.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Valoare înlocuită de <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Timp aproximativ rămas: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index b342287..02ed8eb 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалия (красный/зеленый)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалия (синий/желтый)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Коррекция цвета"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Настройте цветопередачу на экране устройства. Эта функция может помочь:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; сделать цвета более четкими;&lt;/li&gt; &lt;li&gt; убрать цвета, чтобы вам проще было сфокусироваться.&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Настройте цветопередачу на экране устройства. Эта функция может помочь:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;сделать цвета более четкими;&lt;/li&gt; &lt;li&gt;&amp;nbsp;убрать цвета, чтобы вам проще было сфокусироваться.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Новая настройка: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"Уровень заряда – <xliff:g id="PERCENTAGE">%1$s</xliff:g>. <xliff:g id="TIME_STRING">%2$s</xliff:g>."</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Заряда хватит примерно на <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 035a159..b5d77c0 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"වර්ණ දුර්වලතාවය (රතු-කොළ)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"වර්ණ අන්ධතාවය (නිල්-කහ)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"වර්ණ නිවැරදි කිරීම"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"ඔබගේ උපාංගයේ වර්ණ සංදර්ශනය වන ආකාරය සීරුමාරු කරන්න. මෙය ඔබට පහත දේවල් සිදු කිරීමට අවශ්‍ය විට ප්‍රයෝජනවත් විය හැකිය:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; වර්ණ වඩාත් නිවැරදිව බැලීම&lt;/li&gt; &lt;li&gt; ඔබට අවධානය යොමු කිරීමට උදව් වීමට වර්ණ ඉවත් කිරීම&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"ඔබගේ උපාංගයේ වර්ණ සංදර්ශනය වන ආකාරය සීරුමාරු කරන්න. මෙය ඔබට පහත දේවල් සිදු කිරීමට අවශ්‍ය විට ප්‍රයෝජනවත් විය හැකිය:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;වර්ණ වඩාත් නිවැරදිව බැලීම&lt;/li&gt; &lt;li&gt;&amp;nbsp;ඔබට අවධානය යොමු කිරීමට උදව් වීමට වර්ණ ඉවත් කිරීම&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> මගින් ඉක්මවන ලදී"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ක් පමණ ඉතිරියි"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index b24ac8e..4d42623 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomália (červená a zelená)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomália (modrá a žltá)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Úprava farieb"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Upravte si zobrazovanie farieb v zariadení. Môže to byť užitočné, ak chcete:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; zobraziť presnejšie viac farieb;y&lt;/li&gt; &lt;li&gt; odstrániť farby, aby ste sa mohli lepšie sústrediť.&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Upravte si zobrazovanie farieb v zariadení. Môže to byť užitočné, ak chcete:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;presnejšie zobrazovať farby;&lt;/li&gt; &lt;li&gt;&amp;nbsp;odstrániť farby, aby ste sa mohli sústrediť.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Prekonané predvoľbou <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Zostáva približne <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 626402a..b8fb2c4 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalija (rdeča – zelena)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalija (modra – rumena)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Popravljanje barv"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Prilagodite prikaz barv v napravi. To je uporabno, ko želite:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; videti bolj prave barve;&lt;/li&gt; &lt;li&gt; odstraniti barve, da se lažje osredotočite.&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Prilagodite prikaz barv v napravi. To je uporabno, ko želite:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;videti bolj prave barve;&lt;/li&gt; &lt;li&gt;&amp;nbsp;odstraniti barve, da se lažje osredotočite.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Preglasila nastavitev: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Še približno <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 4f22348..95ba023 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomali (e kuqe - e gjelbër)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomali (e kaltër - e verdhë)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korrigjimi i ngjyrës"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Rregullo mënyrën se si ngjyrat afishohen në pajisjen tënde. Kjo mund të jetë e dobishme kur dëshiron që:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; T\'i shikosh ngjyrat me më shumë saktësi&lt;/li&gt; &lt;li&gt; T\'i heqësh ngjyrat për të të ndihmuar të fokusohesh&lt;/li&gt; &lt;/ol&gt;"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (2333641630205214702) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Mbivendosur nga <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Rreth <xliff:g id="TIME_REMAINING">%1$s</xliff:g> të mbetura"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 4f37180c..ab49d94 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалија (црвено-зелено)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалија (плаво-жуто)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Корекција боја"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Прилагодите начин на који се боје приказују на уређају. То може да буде корисно када желите:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; да вам се боје тачније приказују&lt;/li&gt; &lt;li&gt; да уклоните боје како бисте се фокусирали&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Прилагодите начин на који се боје приказују на уређају. То може да буде корисно када желите:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;да вам се боје тачније приказују&lt;/li&gt; &lt;li&gt;&amp;nbsp;да уклоните боје како бисте се фокусирали&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Замењује га <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>–<xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Преостало је око <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 069b6a5..a630706 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomali (rött-grönt)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomali (blått-gult)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Färgkorrigering"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Ändra hur färger visas på enheten. Det kan vara ett bra hjälpmedel när du vill&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; att färger ska visas mer exakt&lt;/li&gt; &lt;li&gt; ta bort färger för att fokusera bättre&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Ändra hur färger visas på enheten. Det kan vara ett bra hjälpmedel när du vill&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;att färger ska visas mer exakt&lt;/li&gt; &lt;li&gt;&amp;nbsp;ta bort färger för att fokusera bättre.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Har åsidosatts av <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Cirka <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kvar"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 0fb620c..ef68434 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (nyekundu-kijani)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (samawati-manjano)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Usahihishaji wa rangi"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Badilisha jinsi rangi zinavyoonekana kwenye kifaa chako. Hali hii inaweza kuwa muhimu unapotaka:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Kuona rangi kwa usahihi zaidi&lt;/li&gt; &lt;li&gt; Kuondoa rangi ili kukusaidia kuwa makini&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Badilisha jinsi rangi zinavyoonekana kwenye kifaa chako. Hali hii inaweza kuwa muhimu unapotaka:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Kuona rangi kwa usahihi zaidi&lt;/li&gt; &lt;li&gt;&amp;nbsp;Kuondoa rangi ili kukusaidia kuwa makini&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Imetanguliwa na <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Zimesalia takribani <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 3106a69..931b43f 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"நிறம் அடையாளங்காண முடியாமை (சிவப்பு-பச்சை)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"நிறம் அடையாளங்காண முடியாமை (நீலம்-மஞ்சள்)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"வண்ணத்திருத்தம்"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"சாதனத்தில் வண்ணங்கள் காண்பிக்கப்படும் விதத்தைச் சரிசெய்யலாம். இதன் மூலம் நீங்கள் விரும்பும்போதெல்லாம்:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; வண்ணங்களை மிகத் தெளிவாகப் பார்க்கலாம்&lt;/li&gt; &lt;li&gt; கவனம் சிதறாமல் இருக்க வண்ணங்களை நீக்கலாம்&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"சாதனத்தில் வண்ணங்கள் காண்பிக்கப்படும் விதத்தைச் சரிசெய்யலாம். இதன் மூலம் நீங்கள் விரும்பும்போதெல்லாம்:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;வண்ணங்களை மிகத் தெளிவாகப் பார்க்கலாம்&lt;/li&gt; &lt;li&gt;கவனம் சிதறாமல் இருக்க வண்ணங்களை நீக்கலாம்&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> மூலம் மேலெழுதப்பட்டது"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"கிட்டத்தட்ட <xliff:g id="TIME_REMAINING">%1$s</xliff:g> மீதமுள்ளது"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 1f78c0c..987ff78a 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -424,7 +424,8 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"ప్రొటానోమలీ (ఎరుపు-ఆకుపచ్చ రంగు)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ట్రైటనోమలీ (నీలం-పసుపు రంగు)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"కలర్ సరిచేయడం"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"మీ పరికరంపై రంగులు కనిపించే విధానాన్ని అడ్జస్ట్ చేయండి. మీకు కావలసినప్పుడు, ఇది సహాయకరంగా ఉంటుంది:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; మరింత ఖచ్చితంగా రంగులను చూడండి&lt;/li&gt; &lt;li&gt; మీరు ఫోకస్ చేయడంలో సహాయపడటానికి రంగులను తీసివేయండి&lt;/li&gt; &lt;/ol&gt;"</string>
+    <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (2333641630205214702) -->
+    <skip />
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ద్వారా భర్తీ చేయబడింది"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> సమయం మిగిలి ఉంది"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 4bd7b6d..53a9605 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"ตาบอดจางสีแดง (สีแดง/เขียว)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ตาบอดจางสีน้ำเงิน (สีน้ำเงิน/เหลือง)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"การแก้สี"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"ปรับวิธีแสดงสีในอุปกรณ์ การดำเนินการนี้จะเป็นประโยชน์เมื่อคุณต้องการดังนี้&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; เห็นสีได้ถูกต้องยิ่งขึ้น&lt;/li&gt; &lt;li&gt; นำสีออกเพื่อช่วยให้เห็นชัดเจนยิ่งขึ้น&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"ปรับวิธีแสดงสีในอุปกรณ์ การดำเนินการนี้จะเป็นประโยชน์เมื่อคุณต้องการดังนี้&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;เห็นสีได้ถูกต้องยิ่งขึ้น&lt;/li&gt; &lt;li&gt;&amp;nbsp;นำสีออกเพื่อช่วยให้เห็นชัดเจนยิ่งขึ้น&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"แทนที่โดย <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"เหลืออีกประมาณ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index e56e5b9..f36d691 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (pula-berde)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (asul-dilaw)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Pagtatama ng kulay"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Isaayos kung paano ipinapakita ang mga kulay sa iyong device. Makakatulong ito kapag gusto mong:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Makakita ng mas tumpak na mga kulay&lt;/li&gt; &lt;li&gt; Mag-alis ng mga kulay para matulungan kang mag-focus&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Isaayos kung paano ipinapakita ang mga kulay sa iyong device. Makakatulong ito kapag gusto mong:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Makakita ng mas tumpak na mga kulay&lt;/li&gt; &lt;li&gt;&amp;nbsp;Mag-alis ng mga kulay para matulungan kang mag-focus&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Na-override ng <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Humigit-kumulang <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ang natitira"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index ef516c4..0c4e7f0 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomali (kırmızı-yeşil)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomali (mavi-sarı)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Renk düzeltme"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Renklerin cihazınızda nasıl görüntüleneceğini düzenleyin Bu, şunları yapmak istediğinizde kullanışlı olur:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Renkleri daha doğru görmek&lt;/li&gt; &lt;li&gt; Odaklanmanıza yardımcı olması için renkleri kaldırmak&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Renklerin cihazınızda nasıl görüntüleneceğini düzenleyin Bu, şunları yapmak istediğinizde kullanışlı olur:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Renkleri daha doğru görmek&lt;/li&gt; &lt;li&gt;&amp;nbsp;Odaklanmanıza yardımcı olması için renkleri kaldırmak&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> tarafından geçersiz kılındı"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Yaklaşık <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kaldı"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 81528ad..7097835 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалія (червоний – зелений)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалія (синій – жовтий)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Корекція кольору"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Налаштуйте відтворення кольорів на екрані пристрою. Це може бути корисно, якщо ви хочете:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; точніше відтворювати кольори;&lt;/li&gt; &lt;li&gt; вилучити кольори, щоб зосередитися на головному.&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Налаштуйте відтворення кольорів на екрані пристрою. Це може бути корисно, якщо ви хочете:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;точніше відтворювати кольори;&lt;/li&gt; &lt;li&gt;&amp;nbsp;вилучити кольори, щоб зосередитися на головному.&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Замінено на <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Залишилося приблизно <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 798c885..0b03d99 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"‏Protanomaly (سرخ سبز)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"‏Tritanomaly (نیلا پیلا)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"رنگ کی اصلاح"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"‏آپ کے آلے پر رنگوں کے ڈسپلے ہونے کے طریقے کو ایڈجسٹ کریں۔ یہ خصوصیت درج ذیل کے لیے مددگار ثابت ہو سکتی ہے:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; جب آپ رنگوں کو مزید درست طریقے سے دیکھنا چاہیں &lt;/li&gt; &lt;li&gt; فوکس کرنے میں مدد کے لیے رنگوں کو ہٹادیں&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"‏آپ کے آلے پر رنگوں کے ڈسپلے ہونے کے طریقے کو ایڈجسٹ کریں۔ یہ درج ذیل کے لیے مددگار ثابت ہوسکتا ہے ‎:&lt;br/&gt;&amp;ltlt;br/&gt; ‎&lt;ol&gt;‎&lt;li&gt;‎جب آپ رنگوں کو مزید درست طریقے سے دیکھنا چاہیں ‎&lt;/li&gt; &lt;li&gt;&amp;nbsp;‎فوکس کرنے میں مدد کرنے کے لئے رنگوں کو ہٹائیں ‎&lt;/li&gt; &lt;/ol&gt;‎"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> کے ذریعہ منسوخ کردیا گیا"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"تقریباً <xliff:g id="TIME_REMAINING">%1$s</xliff:g> باقی ہے"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 6efc0be..4144aac 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaliya (qizil/yashil)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaliya (ko‘k/sariq)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Rangni tuzatish"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Qurilmadagi ranglar qanday chiqishini moslash Bu quyidagi amallarni bajarishga yordam beradi:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Ranglarni yanada aniq koʻrish&lt;/li&gt; &lt;li&gt; Diqqatni jamlash uchun ranglarni olib tashlash&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Qurilmadagi ranglar qanday chiqishini moslash Bu quyidagi amallarni bajarishga yordam beradi:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Ranglarni yanada aniq koʻrish&lt;/li&gt; &lt;li&gt;&amp;nbsp;Diqqatni jamlash uchun ranglarni olib tashlash&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> bilan almashtirildi"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Taxminan <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qoldi"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 148ed89..1afa1fe 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Mù màu đỏ không hoàn toàn (đỏ-xanh lục)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Mù màu (xanh lam-vàng)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Chỉnh màu"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Điều chỉnh cách các màu hiển thị trên thiết bị. Tùy chọn này có thể hữu ích khi bạn muốn:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Xem các màu chính xác hơn&lt;/li&gt; &lt;li&gt; Loại bỏ các màu để giúp bạn tập trung&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Điều chỉnh cách các màu hiển thị trên thiết bị. Tùy chọn này có thể hữu ích khi bạn muốn:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Xem các màu chính xác hơn&lt;/li&gt; &lt;li&gt;&amp;nbsp;Loại bỏ các màu để giúp bạn tập trung&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Bị ghi đè bởi <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Còn khoảng <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 67923c5..a71d543 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"红色弱视(红绿不分)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"蓝色弱视(蓝黄不分)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"色彩校正"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"调整设备上的颜色显示方式。此设置适用于以下情况:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;想要更准确地查看颜色&lt;/li&gt; &lt;li&gt;想要去除颜色,以便集中注意力&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"调整设备上的颜色显示方式。此设置对以下情况有帮助:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;您想更准确地看颜色&lt;/li&gt; &lt;li&gt;&amp;nbsp;您想去除一些颜色,以便集中注意力&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"已被“<xliff:g id="TITLE">%1$s</xliff:g>”覆盖"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"大约还可使用 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index bf69b31..b628c35 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"紅色弱視 (紅綠)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"藍色弱視 (藍黃)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"色彩校正"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"調整裝置顯示顏色嘅方式。呢項設定喺以下情況適用:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; 想令裝置更加準確咁顯示顏色&lt;/li&gt; &lt;li&gt; 移除顏色嚟提高專注力&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"調整裝置顯示顏色嘅方式。呢項設定喺以下情況適用:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;想令裝置更加準確咁顯示顏色&lt;/li&gt; &lt;li&gt;&amp;nbsp;移除顏色嚟提高專注力&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"已由「<xliff:g id="TITLE">%1$s</xliff:g>」覆寫"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"還有大約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index dcfc599..16f405b 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"紅色弱視 (紅-綠)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"藍色弱視 (藍-黃)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"色彩校正"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"調整裝置顯示顏色的方式。這項設定適用於以下情況:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; 想讓裝置更準確地顯示顏色&lt;/li&gt; &lt;li&gt; 移除顏色以提高專注力&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"調整裝置顯示顏色的方式。這項設定適用於以下情況:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;想讓裝置更準確地顯示顏色&lt;/li&gt; &lt;li&gt;&amp;nbsp;移除顏色以提高專注力&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"已改為<xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"還能使用約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 7b0274a..324ebf6 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -424,7 +424,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"I-Protanomaly (bomvu-luhlaza)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"I-Tritanomaly (luhlaza okwesibhakabhaka-phuzi)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Ukulungiswa kombala"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Lungisa indlela imibala eboniswa ngayo kudivayisi yakkho. Lokhu kungaba usizo lapho ufuna:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Ukubona imibala ngokunembilie&lt;/li&gt; &lt;li&gt; Ukususa imibala ukuze ugxile&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Lungisa indlela imibala eboniswa ngayo kudivayisi yakkho. Lokhu kungasiza uma ufuna ukwenza lokhu:<br/><br/> <ol> <li>&amp;nbsp;Ukubona imibala ngokunembe kakhulu</li> <li>&amp;nbsp;Ukususa imibala ukukusiza ukuthi ugxile</li> </ol>"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Igitshezwe ngaphezulu yi-<xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Cishe u-<xliff:g id="TIME_REMAINING">%1$s</xliff:g> osele"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index efa9f3c..d801f1b 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1067,8 +1067,8 @@
         <![CDATA[
         Adjust how colors display on your device. This can be helpful when you want to:<br/><br/>
         <ol>
-            <li> See colors more accurately</li>
-            <li> Remove colors to help you focus</li>
+            <li>&nbsp;See colors more accurately</li>
+            <li>&nbsp;Remove colors to help you focus</li>
         </ol>
         ]]></string>
     <!-- Summary shown for color space correction preference when its value is overridden by another preference [CHAR LIMIT=35] -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index 2528ac1..f180776 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -1496,6 +1496,13 @@
         }
     }
 
+    /**
+     * Whether the packages for the  user have been initialized.
+     */
+    public boolean isUserAdded(int userId) {
+        return mEntriesMap.contains(userId);
+    }
+
     public interface Callbacks {
         void onRunningStateChanged(boolean running);
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 5e2d21b..9c7aac1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -1006,7 +1006,7 @@
 
     private boolean isProfileConnectedFail() {
         return mIsA2dpProfileConnectedFail || mIsHearingAidProfileConnectedFail
-                || mIsHeadsetProfileConnectedFail;
+                || (!isConnectedSapDevice() && mIsHeadsetProfileConnectedFail);
     }
 
     /**
@@ -1149,6 +1149,12 @@
                 BluetoothProfile.STATE_CONNECTED;
     }
 
+    private boolean isConnectedSapDevice() {
+        SapProfile sapProfile = mProfileManager.getSapProfile();
+        return sapProfile != null && sapProfile.getConnectionStatus(mDevice)
+                == BluetoothProfile.STATE_CONNECTED;
+    }
+
     public CachedBluetoothDevice getSubDevice() {
         return mSubDevice;
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 34fdc1e..63cb381 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -441,6 +441,10 @@
         return mHearingAidProfile;
     }
 
+    SapProfile getSapProfile() {
+        return mSapProfile;
+    }
+
     @VisibleForTesting
     HidProfile getHidProfile() {
         return mHidProfile;
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractIpAddressPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractIpAddressPreferenceController.java
index 3bb3a0c..7f12cc8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractIpAddressPreferenceController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractIpAddressPreferenceController.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.net.ConnectivityManager;
+import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.wifi.WifiManager;
 
@@ -28,7 +29,6 @@
 import com.android.settingslib.R;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 
-import java.net.InetAddress;
 import java.util.Iterator;
 
 /**
@@ -93,19 +93,19 @@
      * @return the formatted and newline-separated IP addresses, or null if none.
      */
     private static String getDefaultIpAddresses(ConnectivityManager cm) {
-        LinkProperties prop = cm.getActiveLinkProperties();
+        LinkProperties prop = cm.getLinkProperties(cm.getActiveNetwork());
         return formatIpAddresses(prop);
     }
 
     private static String formatIpAddresses(LinkProperties prop) {
         if (prop == null) return null;
-        Iterator<InetAddress> iter = prop.getAllAddresses().iterator();
+        Iterator<LinkAddress> iter = prop.getAllLinkAddresses().iterator();
         // If there are no entries, return null
         if (!iter.hasNext()) return null;
         // Concatenate all available addresses, newline separated
         StringBuilder addresses = new StringBuilder();
         while (iter.hasNext()) {
-            addresses.append(iter.next().getHostAddress());
+            addresses.append(iter.next().getAddress().getHostAddress());
             if (iter.hasNext()) addresses.append("\n");
         }
         return addresses.toString();
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index d10ff40..5d4078d 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -252,4 +252,8 @@
 
     <!-- Default for Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW -->
     <bool name="def_enable_non_resizable_multi_window">true</bool>
+
+    <!-- Default for Settings.Secure.ACCESSIBILITY_BUTTON_MODE -->
+    <integer name="def_accessibility_button_mode">1</integer>
+
 </resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 400742b..081f3f6 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -3399,7 +3399,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 198;
+            private static final int SETTINGS_VERSION = 199;
 
             private final int mUserId;
 
@@ -4897,6 +4897,36 @@
                     currentVersion = 198;
                 }
 
+                if (currentVersion == 198) {
+                    // Version 198: Set the default value for accessibility button. If the user
+                    // uses accessibility button in the navigation bar to trigger their
+                    // accessibility features (check if ACCESSIBILITY_BUTTON_TARGETS has value)
+                    // then leave accessibility button mode in the navigation bar, otherwise, set it
+                    // to the floating menu.
+                    final SettingsState secureSettings = getSecureSettingsLocked(userId);
+                    final Setting accessibilityButtonMode = secureSettings.getSettingLocked(
+                            Secure.ACCESSIBILITY_BUTTON_MODE);
+                    if (accessibilityButtonMode.isNull()) {
+                        if (isAccessibilityButtonInNavigationBarOn(secureSettings)) {
+                            secureSettings.insertSettingLocked(Secure.ACCESSIBILITY_BUTTON_MODE,
+                                    String.valueOf(
+                                            Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR),
+                                    /*tag= */ null, /* makeDefault= */ false,
+                                    SettingsState.SYSTEM_PACKAGE_NAME);
+                        } else {
+                            final int defAccessibilityButtonMode =
+                                    getContext().getResources().getInteger(
+                                            R.integer.def_accessibility_button_mode);
+                            secureSettings.insertSettingLocked(Secure.ACCESSIBILITY_BUTTON_MODE,
+                                    String.valueOf(defAccessibilityButtonMode), /* tag= */
+                                    null, /* makeDefault= */ true,
+                                    SettingsState.SYSTEM_PACKAGE_NAME);
+                        }
+                    }
+
+                    currentVersion = 199;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
@@ -5075,5 +5105,15 @@
             }
             return items;
         }
+
+        private boolean isAccessibilityButtonInNavigationBarOn(SettingsState secureSettings) {
+            final boolean hasValueInA11yBtnTargets = !TextUtils.isEmpty(
+                    secureSettings.getSettingLocked(
+                            Secure.ACCESSIBILITY_BUTTON_TARGETS).getValue());
+            final int navigationMode = getContext().getResources().getInteger(
+                    com.android.internal.R.integer.config_navBarInteractionMode);
+
+            return hasValueInA11yBtnTargets && (navigationMode != NAV_BAR_MODE_GESTURAL);
+        }
     }
 }
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index cf66bad..b86ae6d 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -430,6 +430,14 @@
     <!-- Permission required for CTS test - FontManagerTest -->
     <uses-permission android:name="android.permission.UPDATE_FONTS" />
 
+    <!-- Permission required for hotword detection service CTS tests -->
+    <uses-permission android:name="android.permission.MANAGE_HOTWORD_DETECTION" />
+
+    <uses-permission android:name="android.permission.MANAGE_APP_HIBERNATION"/>
+
+    <!-- Permission required for CTS test - ResourceObserverNativeTest -->
+    <uses-permission android:name="android.permission.REGISTER_MEDIA_RESOURCE_OBSERVER" />
+
     <application android:label="@string/app_label"
                 android:theme="@android:style/Theme.DeviceDefault.DayNight"
                 android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index e0097df..3904201 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -336,7 +336,7 @@
         </receiver>
 
         <activity android:name=".screenshot.LongScreenshotActivity"
-                  android:theme="@android:style/Theme.DeviceDefault.NoActionBar"
+                  android:theme="@style/LongScreenshotActivity"
                   android:process=":screenshot"
                   android:exported="false"
                   android:finishOnTaskLaunch="true" />
@@ -602,10 +602,8 @@
                 android:resource="@xml/people_space_widget_info" />
         </receiver>
 
-        <!-- Widget service -->
-        <service android:name=".people.widget.PeopleSpaceWidgetService"
-            android:permission="android.permission.BIND_REMOTEVIEWS"
-            android:exported="false" />
+        <receiver android:name=".people.widget.PeopleSpaceWidgetPinnedReceiver"
+            android:enabled="true"/>
 
         <!-- ContentProvider that returns a People Tile preview for a given shortcut -->
         <provider
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml
index 71cdaf5..384e02d 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml
@@ -22,7 +22,6 @@
     android:clipToPadding="false">
 
     <include
-        style="@style/BouncerSecurityContainer"
         layout="@layout/keyguard_host_view"
         android:layout_width="match_parent"
         android:layout_height="wrap_content" />
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
index b6a41c2..6b4fbdb 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
@@ -77,8 +77,9 @@
             android:fontFamily="@font/clock"
             android:typeface="monospace"
             android:elegantTextHeight="false"
+            android:singleLine="true"
             dozeWeight="200"
-            lockScreenWeight="300"
+            lockScreenWeight="400"
         />
     </FrameLayout>
     <FrameLayout
@@ -109,8 +110,6 @@
 
     <com.android.systemui.statusbar.phone.NotificationIconContainer
         android:id="@+id/left_aligned_notification_icon_container"
-        android:paddingStart="16dp"
-        android:paddingEnd="16dp"
         android:layout_width="match_parent"
         android:layout_height="@dimen/notification_shelf_height"
         android:layout_marginTop="@dimen/widget_vertical_padding"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
index 4db2280..9f3ca74 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
@@ -20,8 +20,6 @@
 <!-- This is a view that shows general status information in Keyguard. -->
 <com.android.keyguard.KeyguardSliceView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:paddingStart="16dp"
-    android:paddingEnd="16dp"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:layout_gravity="center_horizontal"
diff --git a/packages/SystemUI/res-keyguard/values-sw600dp/integers.xml b/packages/SystemUI/res-keyguard/values-sw600dp/integers.xml
new file mode 100644
index 0000000..a35fa3a
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/values-sw600dp/integers.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<resources>
+    <!-- This needs to be specified in an integer, rather than a style, as it can change in response
+         to device config changes, and we need to be able to change it without re-inflation.
+
+         0x11 = center -->
+    <integer name="keyguard_host_view_gravity">0x11</integer>
+</resources>
diff --git a/packages/SystemUI/res-keyguard/values-sw600dp/styles.xml b/packages/SystemUI/res-keyguard/values-sw600dp/styles.xml
deleted file mode 100644
index e632e76..0000000
--- a/packages/SystemUI/res-keyguard/values-sw600dp/styles.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<!--
-  ~ Copyright (C) 2014 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
-  -->
-
-<resources>
-    <style name="BouncerSecurityContainer">
-        <item name="android:layout_gravity">center</item>
-    </style>
-</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/values/integers.xml b/packages/SystemUI/res-keyguard/values/integers.xml
new file mode 100644
index 0000000..6f14dc9b
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/values/integers.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<resources>
+    <!-- This needs to be specified in an integer, rather than a style, as it can change in response
+         to device config changes, and we need to be able to change it without re-inflation.
+
+         0x50 = bottom, 0x01 = center_horizontal -->
+    <integer name="keyguard_host_view_gravity">0x51</integer>
+</resources>
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index 8f42cbe..2ffc992 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -100,10 +100,6 @@
         <item name="android:shadowRadius">?attr/shadowRadius</item>
     </style>
 
-    <style name="BouncerSecurityContainer">
-        <item name="android:layout_gravity">center_horizontal|bottom</item>
-    </style>
-
     <style name="PasswordTheme" parent="Theme.SystemUI">
         <item name="android:textColor">?android:attr/textColorPrimary</item>
         <item name="android:colorControlNormal">?android:attr/textColorPrimary</item>
diff --git a/packages/SystemUI/res/drawable/accessibility_floating_menu_background.xml b/packages/SystemUI/res/drawable/accessibility_floating_menu_background.xml
new file mode 100644
index 0000000..5148668
--- /dev/null
+++ b/packages/SystemUI/res/drawable/accessibility_floating_menu_background.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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <corners
+        android:bottomLeftRadius="@dimen/accessibility_floating_menu_small_single_radius"
+        android:bottomRightRadius="0dp"
+        android:topLeftRadius="@dimen/accessibility_floating_menu_small_single_radius"
+        android:topRightRadius="0dp"/>
+    <solid
+        android:color="@color/accessibility_floating_menu_background"/>
+</shape>
diff --git a/packages/SystemUI/res/drawable/brightness_progress_drawable_thick.xml b/packages/SystemUI/res/drawable/brightness_progress_drawable_thick.xml
index 8efe053..73b02f4 100644
--- a/packages/SystemUI/res/drawable/brightness_progress_drawable_thick.xml
+++ b/packages/SystemUI/res/drawable/brightness_progress_drawable_thick.xml
@@ -18,33 +18,20 @@
             android:paddingMode="stack" >
     <item android:id="@android:id/background"
         android:gravity="center_vertical|fill_horizontal">
-        <layer-list>
-            <item>
-                <shape
-                    android:tint="?android:attr/colorControlActivated"
-                    android:alpha="?android:attr/disabledAlpha">
-                    <size android:height="@dimen/rounded_slider_height" />
-                    <solid android:color="@color/white_disabled" />
-                    <corners android:radius="@dimen/rounded_slider_corner_radius" />
-                </shape>
-            </item>
-            <item
-                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">
-                <com.android.systemui.util.AlphaTintDrawableWrapper
-                    android:drawable="@drawable/ic_brightness"
-                    android:tint="?android:attr/colorControlActivated" />
-            </item>
-        </layer-list>
+        <inset
+            android:insetLeft="@dimen/rounded_slider_track_inset"
+            android:insetRight="@dimen/rounded_slider_track_inset" >
+            <shape>
+                <size android:height="@dimen/rounded_slider_track_width" />
+                <corners android:radius="@dimen/rounded_slider_track_corner_radius" />
+                <solid android:color="?android:attr/textColorPrimary" />
+            </shape>
+        </inset>
     </item>
     <item android:id="@android:id/progress"
           android:gravity="center_vertical|fill_horizontal">
-            <clip
+            <com.android.systemui.util.RoundedCornerProgressDrawable
                 android:drawable="@drawable/brightness_progress_full_drawable"
-                android:clipOrientation="horizontal"
-                android:gravity="left"
             />
     </item>
 </layer-list>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml b/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml
index 5bc2773..41140a7 100644
--- a/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml
+++ b/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml
@@ -26,10 +26,10 @@
     </item>
     <item
         android:id="@+id/slider_icon"
-        android:gravity="center_vertical|left"
+        android:gravity="center_vertical|right"
         android:height="@dimen/rounded_slider_icon_size"
         android:width="@dimen/rounded_slider_icon_size"
-        android:left="@dimen/rounded_slider_icon_inset">
+        android:right="@dimen/rounded_slider_icon_inset">
         <com.android.systemui.util.AlphaTintDrawableWrapper
             android:drawable="@drawable/ic_brightness"
             android:tint="?android:attr/colorBackground"
diff --git a/packages/SystemUI/res/drawable/ic_qs_wallet.xml b/packages/SystemUI/res/drawable/ic_qs_wallet.xml
new file mode 100644
index 0000000..e146eab
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_wallet.xml
@@ -0,0 +1,11 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24"
+    android:tint="?attr/colorControlNormal">
+  <path
+      android:fillColor="@android:color/white"
+      android:pathData="M20,4L4,4c-1.11,0 -1.99,0.89 -1.99,2L2,18c0,1.11 0.89,2 2,2h16c1.11,0 2,
+    -0.89 2,-2L22,6c0,-1.11 -0.89,-2 -2,-2zM20,18L4,18v-6h16v6zM20,8L4,8L4,6h16v2z"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/accessibility_floating_menu_item.xml b/packages/SystemUI/res/layout/accessibility_floating_menu_item.xml
new file mode 100644
index 0000000..f7357b2
--- /dev/null
+++ b/packages/SystemUI/res/layout/accessibility_floating_menu_item.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2021 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingStart="@dimen/accessibility_floating_menu_padding"
+    android:paddingEnd="@dimen/accessibility_floating_menu_padding"
+    android:orientation="vertical"
+    android:gravity="center">
+
+    <View
+        android:id="@+id/icon_view"
+        android:layout_width="@dimen/accessibility_floating_menu_small_width_height"
+        android:layout_height="@dimen/accessibility_floating_menu_small_width_height"/>
+
+    <View
+        android:id="@+id/transparent_divider"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/accessibility_floating_menu_padding"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/long_screenshot.xml b/packages/SystemUI/res/layout/long_screenshot.xml
index 7ba28a8..19bcf95 100644
--- a/packages/SystemUI/res/layout/long_screenshot.xml
+++ b/packages/SystemUI/res/layout/long_screenshot.xml
@@ -24,51 +24,27 @@
 
     <Button
         android:id="@+id/save"
+        style="@android:style/Widget.DeviceDefault.Button.Colored"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="@string/save"
-        app:layout_constraintEnd_toStartOf="@id/cancel"
-        app:layout_constraintHorizontal_chainStyle="packed"
+        android:layout_marginLeft="8dp"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintBottom_toTopOf="@id/guideline" />
+        app:layout_constraintBottom_toTopOf="@id/preview" />
 
-    <Button
-        android:id="@+id/cancel"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:text="@string/cancel"
-        app:layout_constraintEnd_toStartOf="@id/edit"
-        app:layout_constraintStart_toEndOf="@id/save"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintBottom_toTopOf="@id/guideline" />
-
-    <Button
-        android:id="@+id/edit"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:text="@string/screenshot_edit_label"
-        app:layout_constraintEnd_toStartOf="@id/share"
-        app:layout_constraintStart_toEndOf="@id/cancel"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintBottom_toTopOf="@id/guideline" />
-
-    <Button
+    <ImageButton
         android:id="@+id/share"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:text="@*android:string/share"
+        style="@android:style/Widget.Material.Button.Borderless"
+        android:tint="?android:textColorPrimary"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:padding="6dp"
+        android:src="@drawable/ic_screenshot_share"
+        android:layout_marginRight="8dp"
         app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toEndOf="@+id/edit"
         app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintBottom_toTopOf="@id/guideline" />
-
-    <androidx.constraintlayout.widget.Guideline
-        android:id="@+id/guideline"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal"
-        app:layout_constraintGuide_percent="0.1" />
+        app:layout_constraintBottom_toTopOf="@id/preview" />
 
     <ImageView
         android:id="@+id/preview"
@@ -78,7 +54,7 @@
         android:layout_marginHorizontal="48dp"
         app:layout_constrainedHeight="true"
         app:layout_constrainedWidth="true"
-        app:layout_constraintTop_toBottomOf="@id/guideline"
+        app:layout_constraintTop_toBottomOf="@id/save"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintBottom_toBottomOf="parent"
@@ -93,7 +69,7 @@
         android:layout_marginBottom="42dp"
         app:layout_constrainedHeight="true"
         app:layout_constrainedWidth="true"
-        app:layout_constraintTop_toBottomOf="@id/guideline"
+        app:layout_constraintTop_toTopOf="@id/preview"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintBottom_toBottomOf="parent"
@@ -110,7 +86,7 @@
         android:layout_width="200dp"
         android:layout_height="200dp"
         android:elevation="2dp"
-        app:layout_constraintTop_toBottomOf="@id/guideline"
+        app:layout_constraintTop_toTopOf="@id/preview"
         app:layout_constraintLeft_toLeftOf="parent"
         app:handleThickness="@dimen/screenshot_crop_handle_thickness"
         app:handleColor="@*android:color/accent_device_default"
@@ -119,5 +95,24 @@
         app:borderColor="#fff"
         />
 
+    <Button
+        android:id="@+id/edit"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="8dp"
+        style="@android:style/Widget.DeviceDefault.Button.Colored"
+        android:backgroundTint="?android:colorBackground"
+        android:drawableStart="@drawable/ic_screenshot_edit"
+        android:drawableTint="?android:textColorPrimary"
+        android:paddingStart="16dp"
+        android:paddingEnd="8dp"
+        android:paddingVertical="8dp"
+        android:textColor="?android:textColorPrimary"
+        android:text="@string/screenshot_edit_label"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+    />
+
 </androidx.constraintlayout.widget.ConstraintLayout>
 
diff --git a/packages/SystemUI/res/layout/notif_half_shelf.xml b/packages/SystemUI/res/layout/notif_half_shelf.xml
index d36c1a8..42f14f3 100644
--- a/packages/SystemUI/res/layout/notif_half_shelf.xml
+++ b/packages/SystemUI/res/layout/notif_half_shelf.xml
@@ -67,7 +67,7 @@
                     android:textSize="15sp"
                     android:ellipsize="end"
                     android:maxLines="1"
-                    style="@style/TextAppearance.NotificationInfo.Title" />
+                    style="@style/TextAppearance.NotificationImportanceChannel" />
 
                 <Switch
                     android:id="@+id/toggle"
@@ -80,7 +80,7 @@
             <View
                 android:layout_width="match_parent"
                 android:layout_height="1dp"
-                android:background="@color/notification_channel_dialog_separator"
+                android:background="?android:attr/colorAccent"
             />
 
             <!-- ChannelRows get added dynamically -->
@@ -90,7 +90,7 @@
         <View
             android:layout_width="match_parent"
             android:layout_height="1dp"
-            android:background="@color/notification_channel_dialog_separator"
+            android:background="?android:attr/colorAccent"
         />
         <RelativeLayout
             android:id="@+id/bottom_actions"
diff --git a/packages/SystemUI/res/layout/notif_half_shelf_row.xml b/packages/SystemUI/res/layout/notif_half_shelf_row.xml
index c863e02..87de286 100644
--- a/packages/SystemUI/res/layout/notif_half_shelf_row.xml
+++ b/packages/SystemUI/res/layout/notif_half_shelf_row.xml
@@ -53,7 +53,7 @@
             android:textSize="14sp"
             android:ellipsize="end"
             android:maxLines="1"
-            style="@style/TextAppearance.NotificationInfo.Title"
+            style="@style/TextAppearance.NotificationImportanceChannel"
         />
 
         <TextView
@@ -67,7 +67,7 @@
             android:ellipsize="end"
             android:maxLines="1"
             android:layout_below="@id/channel_name"
-            style="@style/TextAppearance.NotificationInfo.Secondary"
+            style="@style/TextAppearance.NotificationImportanceApp"
         />
     </RelativeLayout>
 
diff --git a/packages/SystemUI/res/raw/image_wallpaper_fragment_shader.glsl b/packages/SystemUI/res/raw/image_wallpaper_fragment_shader.glsl
index e4b6e07..e9c8389 100644
--- a/packages/SystemUI/res/raw/image_wallpaper_fragment_shader.glsl
+++ b/packages/SystemUI/res/raw/image_wallpaper_fragment_shader.glsl
@@ -1,11 +1,54 @@
 precision mediump float;
+#define GAMMA 2.2
+#define INV_GAMMA 1.0 / GAMMA
 
 // The actual wallpaper texture.
 uniform sampler2D uTexture;
+uniform float uExposure;
 
 varying vec2 vTextureCoordinates;
 
+// Following the Rec. ITU-R BT.709.
+float relativeLuminance(vec3 color) {
+    return 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b;
+}
+
+// Adjusts the exposure of some luminance value.
+float relativeExposureCompensation(in float lum, in float ev) {
+    return lum * pow(2.0, ev);
+}
+
+vec4 srgbToLinear(in vec4 color) {
+    vec4 linearColor = vec4(color);
+    linearColor.rgb = pow(linearColor.rgb, vec3(GAMMA));
+    return linearColor;
+}
+
+vec4 linearToSrgb(in vec4 color) {
+    vec4 srgbColor = vec4(color);
+        srgbColor.rgb = pow(srgbColor.rgb, vec3(INV_GAMMA));
+        return srgbColor;
+}
+
+/*
+ * Normalizes a value inside a range to a normalized range [0,1].
+ */
+float normalizedRange(in float value, in float inMin, in float inMax) {
+    float valueClamped = clamp(value, inMin, inMax);
+    return (value - inMin) / (inMax - inMin);
+}
+
 void main() {
-    // gets the pixel value of the wallpaper for this uv coordinates on screen.
-    gl_FragColor = texture2D(uTexture, vTextureCoordinates);
+    // Gets the pixel value of the wallpaper for this uv coordinates on screen.
+    vec4 color = srgbToLinear(texture2D(uTexture, vTextureCoordinates));
+    float lum = relativeLuminance(color.rgb);
+
+    // Transform it using the S curve created by the smoothstep. This will increase the contrast.
+    lum = smoothstep(0., 1., lum) + 0.001;
+
+    lum = relativeExposureCompensation(lum, mix(-15., 10., uExposure));
+    lum = mix(clamp(lum, 0.0, 1.0), 1.0, normalizedRange(uExposure, 0.55, 1.0));
+    color.rgb *= lum;
+
+    gl_FragColor = linearToSrgb(color);
 }
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index 37ec576..d571f2f 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -102,4 +102,6 @@
     <color name="privacy_circle_camera">#81C995</color> <!-- g300 -->
     <color name="privacy_circle_microphone_location">#FCAD70</color> <!--o300 -->
 
+    <!-- Accessibility floating menu -->
+    <color name="accessibility_floating_menu_background">#B3000000</color> <!-- 70% -->
 </resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index d478319..0076c51 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -115,8 +115,6 @@
 
     <color name="notification_section_header_label_color">@color/GM2_grey_900</color>
     <color name="notification_section_clear_all_btn_color">@color/GM2_grey_700</color>
-    <!-- The divider view for the notification channel editor half-shelf -->
-    <color name="notification_channel_dialog_separator">@color/GM2_grey_200</color>
 
     <color name="assist_orb_color">#ffffff</color>
 
@@ -276,4 +274,8 @@
     <!-- TODO(b/178093014) Colors for privacy dialog. These should be changed to the new palette -->
     <color name="privacy_circle_camera">#1E8E3E</color> <!-- g600 -->
     <color name="privacy_circle_microphone_location">#E8710A</color> <!--o600 -->
+
+    <!-- Accessibility floating menu -->
+    <color name="accessibility_floating_menu_background">#CCFFFFFF</color> <!-- 80% -->
+    <color name="accessibility_floating_menu_stroke_dark">#26FFFFFF</color> <!-- 15% -->
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index b0c5239..af6df32 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -107,7 +107,7 @@
 
     <!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
     <string name="quick_settings_tiles_stock" translatable="false">
-        wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,dark,work,cast,night,screenrecord,reverse,reduce_brightness,cameratoggle,mictoggle,controls,alarm
+        wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,dark,work,cast,night,screenrecord,reverse,reduce_brightness,cameratoggle,mictoggle,controls,alarm,wallet
     </string>
 
     <!-- The tiles to display in QuickSettings -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 2062104..b050945 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1356,11 +1356,28 @@
     <dimen name="people_space_image_radius">20dp</dimen>
     <dimen name="people_space_widget_background_padding">6dp</dimen>
 
-    <dimen name="rounded_slider_height">48dp</dimen>
+    <!-- Accessibility floating menu -->
+    <dimen name="accessibility_floating_menu_elevation">5dp</dimen>
+    <dimen name="accessibility_floating_menu_stroke_width">1dp</dimen>
+    <dimen name="accessibility_floating_menu_stroke_inset">-2dp</dimen>
+    <dimen name="accessibility_floating_menu_margin">16dp</dimen>
+    <dimen name="accessibility_floating_menu_padding">6dp</dimen>
+    <dimen name="accessibility_floating_menu_small_width_height">36dp</dimen>
+    <dimen name="accessibility_floating_menu_small_single_radius">25dp</dimen>
+    <dimen name="accessibility_floating_menu_small_multiple_radius">20dp</dimen>
+    <dimen name="accessibility_floating_menu_large_width_height">56dp</dimen>
+    <dimen name="accessibility_floating_menu_large_single_radius">33dp</dimen>
+    <dimen name="accessibility_floating_menu_large_multiple_radius">35dp</dimen>
+
+    <dimen name="rounded_slider_height">44dp</dimen>
     <!-- rounded_slider_height / 2 -->
-    <dimen name="rounded_slider_corner_radius">24dp</dimen>
-    <!-- rounded_slider_height / 2 -->
-    <dimen name="rounded_slider_icon_size">24dp</dimen>
-    <!-- rounded_slider_icon_size / 2 -->
+    <dimen name="rounded_slider_corner_radius">22dp</dimen>
+    <dimen name="rounded_slider_icon_size">20dp</dimen>
+    <!-- (rounded_slider_height - rounded_slider_icon_size) / 2 -->
     <dimen name="rounded_slider_icon_inset">12dp</dimen>
+    <!-- rounded_slider_corner_radius - rounded_slider_track_corner_radius -->
+    <dimen name="rounded_slider_track_inset">18dp</dimen>
+    <dimen name="rounded_slider_track_width">8dp</dimen>
+    <!-- rounded_slider_track_width / 2 -->
+    <dimen name="rounded_slider_track_corner_radius">4dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml
index 8cd5757..52a97b1 100644
--- a/packages/SystemUI/res/values/flags.xml
+++ b/packages/SystemUI/res/values/flags.xml
@@ -38,6 +38,8 @@
     <!-- People Tile flag -->
     <bool name="flag_conversations">false</bool>
 
+    <bool name="flag_wallet">false</bool>
+
     <!-- The new animations to/from lockscreen and AOD! -->
     <bool name="flag_lockscreen_animations">false</bool>
 
@@ -48,4 +50,6 @@
     <bool name="flag_pm_lite">false</bool>
 
     <bool name="flag_alarm_tile">false</bool>
+
+    <bool name="flag_charging_ripple">false</bool>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 87fa4f8..691d111 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -958,8 +958,6 @@
     <string name="quick_settings_dark_mode_secondary_label_on_at">On at <xliff:g id="time" example="10 pm">%s</xliff:g></string>
     <!-- QuickSettings: Secondary text for when the Dark theme or some other tile will be on until some user-selected time. [CHAR LIMIT=20] -->
     <string name="quick_settings_dark_mode_secondary_label_until">Until <xliff:g id="time" example="7 am">%s</xliff:g></string>
-    <!-- QuickSettings: Label for the toggle that controls whether Reduce Brightness is enabled. [CHAR LIMIT=NONE] -->
-    <string name="quick_settings_reduce_bright_colors_label">Reduce brightness</string>
 
     <!-- QuickSettings: NFC tile [CHAR LIMIT=NONE] -->
     <string name="quick_settings_nfc_label">NFC</string>
@@ -1621,6 +1619,12 @@
     <!-- Name of the alarm status bar icon. -->
     <string name="status_bar_alarm">Alarm</string>
 
+    <!-- Wallet strings -->
+    <!-- Wallet empty state, title [CHAR LIMIT=32] -->
+    <string name="wallet_title">Wallet</string>
+    <!-- Secondary label of the quick access wallet tile. [CHAR LIMIT=32] -->
+    <string name="wallet_secondary_label">Ready</string>
+
     <!-- Name of the work status bar icon. -->
     <string name="status_bar_work">Work profile</string>
 
@@ -2667,6 +2671,12 @@
     <!-- Click action label for magnification switch. [CHAR LIMIT=NONE] -->
     <string name="magnification_mode_switch_click_label">Switch</string>
 
+    <!-- Accessibility floating menu strings -->
+    <!-- Message for the accessibility floating button migration tooltip. It shows when the user use gestural navigation then upgrade their system. It will tell the user the accessibility gesture had been replaced by accessibility floating button. [CHAR LIMIT=100] -->
+    <string name="accessibility_floating_button_migration_tooltip">Accessibility button replaced the accessibility gesture\n\n<annotation id="link">View settings</annotation></string>
+    <!-- Message for the accessibility floating button docking tooltip. It shows when the user first time drag the button. It will tell the user about docking behavior. [CHAR LIMIT=70] -->
+    <string name="accessibility_floating_button_docking_tooltip">Move button to the edge to hide it temporarily</string>
+
     <!-- Device Controls strings -->
     <!-- Device Controls empty state, title [CHAR LIMIT=30] -->
     <string name="quick_controls_title">Device controls</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index ff9ea01..4a661dc 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -610,6 +610,11 @@
         <item name="android:windowCloseOnTouchOutside">true</item>
     </style>
 
+    <!-- Screenshots -->
+    <style name="LongScreenshotActivity" parent="@android:style/Theme.DeviceDefault.DayNight">
+        <item name="android:windowNoTitle">true</item>
+    </style>
+
     <!-- Privacy dialog -->
     <style name="PrivacyDialog" parent="ScreenRecord">
         <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index 09e9675a..f98a959 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -41,6 +41,7 @@
     srcs: [
         "src/**/*.java",
         "src/**/I*.aidl",
+        ":wm_shell-aidls",
     ],
 
     static_libs: [
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index 5126284..3da3085 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -16,11 +16,6 @@
 
 package com.android.systemui.shared.recents;
 
-import android.app.PendingIntent;
-import android.app.PictureInPictureParams;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
 import android.graphics.Bitmap;
 import android.graphics.Insets;
 import android.graphics.Rect;
@@ -28,26 +23,15 @@
 import android.os.UserHandle;
 import android.view.MotionEvent;
 
-import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
-import com.android.systemui.shared.recents.ISplitScreenListener;
-import com.android.systemui.shared.recents.IStartingWindowListener;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.system.RemoteTransitionCompat;
 
 /**
  * Temporary callbacks into SystemUI.
- * Next id = 44
  */
 interface ISystemUiProxy {
 
     /**
-     * Proxies SurfaceControl.screenshotToBuffer().
-     * @Removed
-     * GraphicBufferCompat screenshot(in Rect sourceCrop, int width, int height, int minLayer,
-     *             int maxLayer, boolean useIdentityTransform, int rotation) = 0;
-     */
-
-    /**
      * Begins screen pinning on the provided {@param taskId}.
      */
     void startScreenPinning(int taskId) = 1;
@@ -115,11 +99,6 @@
     void stopScreenPinning() = 17;
 
     /**
-     * Sets the shelf height and visibility.
-     */
-    void setShelfHeight(boolean visible, int shelfHeight) = 20;
-
-    /**
      * Handle the provided image as if it was a screenshot.
      *
      * Deprecated, use handleImageBundleAsScreenshot with image bundle and UserTask
@@ -139,27 +118,12 @@
     void notifySwipeToHomeFinished() = 23;
 
     /**
-     * Sets listener to get pinned stack animation callbacks.
-     */
-    void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) = 24;
-
-    /**
      * Notifies that quickstep will switch to a new task
      * @param rotation indicates which Surface.Rotation the gesture was started in
      */
     void onQuickSwitchToNewTask(int rotation) = 25;
 
     /**
-     * Start the one-handed mode.
-     */
-    void startOneHandedMode() = 26;
-
-    /**
-     * Stop the one-handed mode.
-     */
-    void stopOneHandedMode() = 27;
-
-    /**
      * Handle the provided image as if it was a screenshot.
      */
     void handleImageBundleAsScreenshot(in Bundle screenImageBundle, in Rect locationInScreen,
@@ -170,88 +134,5 @@
      */
     void expandNotificationPanel() = 29;
 
-    /**
-     * Notifies that Activity is about to be swiped to home with entering PiP transition and
-     * queries the destination bounds for PiP depends on Launcher's rotation and shelf height.
-     *
-     * @param componentName ComponentName represents the Activity
-     * @param activityInfo ActivityInfo tied to the Activity
-     * @param pictureInPictureParams PictureInPictureParams tied to the Activity
-     * @param launcherRotation Launcher rotation to calculate the PiP destination bounds
-     * @param shelfHeight Shelf height of launcher to calculate the PiP destination bounds
-     * @return destination bounds the PiP window should land into
-     */
-    Rect startSwipePipToHome(in ComponentName componentName, in ActivityInfo activityInfo,
-                in PictureInPictureParams pictureInPictureParams,
-                int launcherRotation, int shelfHeight) = 30;
-
-    /**
-     * Notifies the swiping Activity to PiP onto home transition is finished
-     *
-     * @param componentName ComponentName represents the Activity
-     * @param destinationBounds the destination bounds the PiP window lands into
-     */
-    void stopSwipePipToHome(in ComponentName componentName, in Rect destinationBounds) = 31;
-
-    /**
-     * Registers a RemoteTransitionCompat that will handle transitions. This parameter bundles an
-     * IRemoteTransition and a filter that must pass for it.
-     */
-    void registerRemoteTransition(in RemoteTransitionCompat remoteTransition) = 32;
-
-    /** Unegisters a RemoteTransitionCompat that will handle transitions. */
-    void unregisterRemoteTransition(in RemoteTransitionCompat remoteTransition) = 33;
-
-// SplitScreen APIs...copied from SplitScreen.java
-    /**
-     * Stage position isn't specified normally meaning to use what ever it is currently set to.
-     */
-    //int STAGE_POSITION_UNDEFINED = -1;
-    /**
-     * Specifies that a stage is positioned at the top half of the screen if
-     * in portrait mode or at the left half of the screen if in landscape mode.
-     */
-    //int STAGE_POSITION_TOP_OR_LEFT = 0;
-    /**
-     * Specifies that a stage is positioned at the bottom half of the screen if
-     * in portrait mode or at the right half of the screen if in landscape mode.
-     */
-    //int STAGE_POSITION_BOTTOM_OR_RIGHT = 1;
-
-    /**
-     * Stage type isn't specified normally meaning to use what ever the default is.
-     * E.g. exit split-screen and launch the app in fullscreen.
-     */
-    //int STAGE_TYPE_UNDEFINED = -1;
-    /**
-     * The main stage type.
-     * @see MainStage
-     */
-    //int STAGE_TYPE_MAIN = 0;
-    /**
-     * The side stage type.
-     * @see SideStage
-     */
-    //int STAGE_TYPE_SIDE = 1;
-
-    void registerSplitScreenListener(in ISplitScreenListener listener) = 34;
-    void unregisterSplitScreenListener(in ISplitScreenListener listener) = 35;
-
-    /** Hides the side-stage if it is currently visible. */
-    void setSideStageVisibility(in boolean visible) = 36;
-    /** Removes the split-screen stages. */
-    void exitSplitScreen() = 37;
-    /** @param exitSplitScreenOnHide if to exit split-screen if both stages are not visible. */
-    void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) = 38;
-    void startTask(in int taskId, in int stage, in int position, in Bundle options) = 39;
-    void startShortcut(in String packageName, in String shortcutId, in int stage, in int position,
-            in Bundle options, in UserHandle user) = 40;
-    void startIntent(
-            in PendingIntent intent, in Intent fillInIntent, in int stage, in int position,
-            in Bundle options) = 41;
-    void removeFromSideStage(in int taskId) = 42;
-    /**
-     * Sets listener to get task launching callbacks.
-     */
-    void setStartingWindowListener(IStartingWindowListener listener) = 43;
+    // Next id = 44
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index 937c1df..41840af 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -41,6 +41,18 @@
     public static final String KEY_EXTRA_INPUT_MONITOR = "extra_input_monitor";
     public static final String KEY_EXTRA_WINDOW_CORNER_RADIUS = "extra_window_corner_radius";
     public static final String KEY_EXTRA_SUPPORTS_WINDOW_CORNERS = "extra_supports_window_corners";
+    // See IPip.aidl
+    public static final String KEY_EXTRA_SHELL_PIP = "extra_shell_pip";
+    // See ISplitScreen.aidl
+    public static final String KEY_EXTRA_SHELL_SPLIT_SCREEN = "extra_shell_split_screen";
+    // See IOneHanded.aidl
+    public static final String KEY_EXTRA_SHELL_ONE_HANDED = "extra_shell_one_handed";
+    // See IShellTransitions.aidl
+    public static final String KEY_EXTRA_SHELL_SHELL_TRANSITIONS =
+            "extra_shell_shell_transitions";
+    // See IStartingWindow.aidl
+    public static final String KEY_EXTRA_SHELL_STARTING_WINDOW =
+            "extra_shell_starting_window";
 
     public static final String NAV_BAR_MODE_2BUTTON_OVERLAY =
             WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
index 400bf15..2f38f0a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
@@ -23,6 +23,7 @@
 import static android.view.WindowManager.TRANSIT_TO_BACK;
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
 import static android.view.WindowManager.TransitionOldType;
+import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
 
 import android.os.RemoteException;
 import android.util.Log;
@@ -35,6 +36,8 @@
 import android.window.IRemoteTransitionFinishedCallback;
 import android.window.TransitionInfo;
 
+import java.util.ArrayList;
+
 /**
  * @see RemoteAnimationAdapter
  */
@@ -100,6 +103,52 @@
         };
     }
 
+    private static class CounterRotator {
+        SurfaceControl mSurface = null;
+        ArrayList<SurfaceControl> mRotateChildren = null;
+
+        void setup(SurfaceControl.Transaction t, SurfaceControl parent, int rotateDelta,
+                float displayW, float displayH) {
+            if (rotateDelta == 0) return;
+            mRotateChildren = new ArrayList<>();
+            // We want to counter-rotate, so subtract from 4
+            rotateDelta = 4 - (rotateDelta + 4) % 4;
+            mSurface = new SurfaceControl.Builder()
+                    .setName("Transition Unrotate")
+                    .setContainerLayer()
+                    .setParent(parent)
+                    .build();
+            // column-major
+            if (rotateDelta == 1) {
+                t.setMatrix(mSurface, 0, 1, -1, 0);
+                t.setPosition(mSurface, displayW, 0);
+            } else if (rotateDelta == 2) {
+                t.setMatrix(mSurface, -1, 0, 0, -1);
+                t.setPosition(mSurface, displayW, displayH);
+            } else if (rotateDelta == 3) {
+                t.setMatrix(mSurface, 0, -1, 1, 0);
+                t.setPosition(mSurface, 0, displayH);
+            }
+            t.show(mSurface);
+        }
+
+        void addChild(SurfaceControl.Transaction t, SurfaceControl child) {
+            if (mSurface == null) return;
+            t.reparent(child, mSurface);
+            mRotateChildren.add(child);
+        }
+
+        void cleanUp(SurfaceControl rootLeash) {
+            if (mSurface == null) return;
+            SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+            for (int i = mRotateChildren.size() - 1; i >= 0; --i) {
+                t.reparent(mRotateChildren.get(i), rootLeash);
+            }
+            t.remove(mSurface);
+            t.apply();
+        }
+    }
+
     private static IRemoteTransition.Stub wrapRemoteTransition(
             final RemoteAnimationRunnerCompat remoteAnimationAdapter) {
         return new IRemoteTransition.Stub() {
@@ -116,17 +165,46 @@
 
                 // TODO(b/177438007): Move this set-up logic into launcher's animation impl.
                 boolean isReturnToHome = false;
+                TransitionInfo.Change launcherTask = null;
+                TransitionInfo.Change wallpaper = null;
+                int launcherLayer = 0;
+                int rotateDelta = 0;
+                float displayW = 0;
+                float displayH = 0;
                 for (int i = info.getChanges().size() - 1; i >= 0; --i) {
                     final TransitionInfo.Change change = info.getChanges().get(i);
                     if (change.getTaskInfo() != null
                             && change.getTaskInfo().getActivityType() == ACTIVITY_TYPE_HOME) {
                         isReturnToHome = change.getMode() == TRANSIT_OPEN
                                 || change.getMode() == TRANSIT_TO_FRONT;
-                        break;
+                        launcherTask = change;
+                        launcherLayer = info.getChanges().size() - i;
+                    } else if ((change.getFlags() & FLAG_IS_WALLPAPER) != 0) {
+                        wallpaper = change;
+                    }
+                    if (change.getParent() == null && change.getEndRotation() >= 0
+                            && change.getEndRotation() != change.getStartRotation()) {
+                        rotateDelta = change.getEndRotation() - change.getStartRotation();
+                        displayW = change.getEndAbsBounds().width();
+                        displayH = change.getEndAbsBounds().height();
+                    }
+                }
+
+                // Prepare for rotation if there is one
+                final CounterRotator counterLauncher = new CounterRotator();
+                final CounterRotator counterWallpaper = new CounterRotator();
+                if (launcherTask != null && rotateDelta != 0 && launcherTask.getParent() != null) {
+                    counterLauncher.setup(t, info.getChange(launcherTask.getParent()).getLeash(),
+                            rotateDelta, displayW, displayH);
+                    if (counterLauncher.mSurface != null) {
+                        t.setLayer(counterLauncher.mSurface, launcherLayer);
                     }
                 }
 
                 if (isReturnToHome) {
+                    if (counterLauncher.mSurface != null) {
+                        t.setLayer(counterLauncher.mSurface, info.getChanges().size() * 3);
+                    }
                     // Need to "boost" the closing things since that's what launcher expects.
                     for (int i = info.getChanges().size() - 1; i >= 0; --i) {
                         final TransitionInfo.Change change = info.getChanges().get(i);
@@ -136,6 +214,7 @@
                         if (!TransitionInfo.isIndependent(change, info)) continue;
                         if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) {
                             t.setLayer(leash, info.getChanges().size() * 3 - i);
+                            counterLauncher.addChild(t, leash);
                         }
                     }
                     // Make wallpaper visible immediately since launcher apparently won't do this.
@@ -143,6 +222,18 @@
                         t.show(wallpapersCompat[i].leash.getSurfaceControl());
                         t.setAlpha(wallpapersCompat[i].leash.getSurfaceControl(), 1.f);
                     }
+                } else {
+                    if (launcherTask != null) {
+                        counterLauncher.addChild(t, launcherTask.getLeash());
+                    }
+                    if (wallpaper != null && rotateDelta != 0 && wallpaper.getParent() != null) {
+                        counterWallpaper.setup(t, info.getChange(wallpaper.getParent()).getLeash(),
+                                rotateDelta, displayW, displayH);
+                        if (counterWallpaper.mSurface != null) {
+                            t.setLayer(counterWallpaper.mSurface, -1);
+                            counterWallpaper.addChild(t, wallpaper.getLeash());
+                        }
+                    }
                 }
                 t.apply();
 
@@ -150,6 +241,8 @@
                     @Override
                     public void run() {
                         try {
+                            counterLauncher.cleanUp(info.getRootLeash());
+                            counterWallpaper.cleanUp(info.getRootLeash());
                             finishCallback.onTransitionFinished(null /* wct */);
                         } catch (RemoteException e) {
                             Log.e("ActivityOptionsCompat", "Failed to call app controlled animation"
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
index 87f6b82..246476a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
@@ -56,6 +56,7 @@
     public final boolean isNotInRecents;
     public final Rect contentInsets;
     public final PictureInPictureParams pictureInPictureParams;
+    public final int rotationChange;
 
     private final SurfaceControl mStartLeash;
 
@@ -74,6 +75,7 @@
         contentInsets = app.contentInsets;
         activityType = app.windowConfiguration.getActivityType();
         pictureInPictureParams = app.pictureInPictureParams;
+        rotationChange = 0;
 
         mStartLeash = app.startLeash;
     }
@@ -102,7 +104,7 @@
         localBounds = new Rect(change.getEndAbsBounds());
         localBounds.offsetTo(change.getEndRelOffset().x, change.getEndRelOffset().y);
         sourceContainerBounds = null;
-        screenSpaceBounds = change.getEndAbsBounds();
+        screenSpaceBounds = new Rect(change.getEndAbsBounds());
         prefixOrderIndex = order;
         // TODO(shell-transitions): I guess we need to send content insets? evaluate how its used.
         contentInsets = new Rect(0, 0, 0, 0);
@@ -115,6 +117,7 @@
         }
         pictureInPictureParams = null;
         mStartLeash = null;
+        rotationChange = change.getEndRotation() - change.getStartRotation();
     }
 
     public static RemoteAnimationTargetCompat[] wrap(RemoteAnimationTarget[] apps) {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java
index 255fffd..fa2f32f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java
@@ -99,11 +99,6 @@
         return this;
     }
 
-    @Deprecated
-    public TransactionCompat setEarlyWakeup() {
-        return this;
-    }
-
     public TransactionCompat setColor(SurfaceControlCompat surfaceControl, float[] color) {
         mTransaction.setColor(surfaceControl.mSurfaceControl, color);
         return this;
@@ -118,8 +113,4 @@
             SurfaceControl relativeTo, int z) {
         t.setRelativeLayer(surfaceControl, relativeTo, z);
     }
-
-    @Deprecated
-    public static void setEarlyWakeup(Transaction t) {
-    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java b/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java
index 64b3d73..c918d98 100644
--- a/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java
+++ b/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java
@@ -38,8 +38,10 @@
  * The time's text color is a gradient that changes its colors based on its controller.
  */
 public class AnimatableClockView extends TextView {
-    private static final CharSequence FORMAT_12_HOUR = "hh\nmm";
-    private static final CharSequence FORMAT_24_HOUR = "HH\nmm";
+    private static final CharSequence DOUBLE_LINE_FORMAT_12_HOUR = "hh\nmm";
+    private static final CharSequence DOUBLE_LINE_FORMAT_24_HOUR = "HH\nmm";
+    private static final CharSequence SINGLE_LINE_FORMAT_12_HOUR = "h:mm";
+    private static final CharSequence SINGLE_LINE_FORMAT_24_HOUR = "H:mm";
     private static final long ANIM_DURATION = 300;
 
     private final Calendar mTime = Calendar.getInstance();
@@ -55,6 +57,8 @@
     private TextAnimator mTextAnimator = null;
     private Runnable mOnTextAnimatorInitialized;
 
+    private boolean mIsSingleLine;
+
     public AnimatableClockView(Context context) {
         this(context, null, 0, 0);
     }
@@ -78,6 +82,15 @@
         } finally {
             ta.recycle();
         }
+
+        ta = context.obtainStyledAttributes(
+                attrs, android.R.styleable.TextView, defStyleAttr, defStyleRes);
+        try {
+            mIsSingleLine = ta.getBoolean(android.R.styleable.TextView_singleLine, false);
+        } finally {
+            ta.recycle();
+        }
+
         refreshFormat();
     }
 
@@ -171,7 +184,16 @@
 
     void refreshFormat() {
         final boolean use24HourFormat = DateFormat.is24HourFormat(getContext());
-        mFormat =  use24HourFormat ? FORMAT_24_HOUR : FORMAT_12_HOUR;
+        if (mIsSingleLine && use24HourFormat) {
+            mFormat = SINGLE_LINE_FORMAT_24_HOUR;
+        } else if (!mIsSingleLine && use24HourFormat) {
+            mFormat = DOUBLE_LINE_FORMAT_24_HOUR;
+        } else if (mIsSingleLine && !use24HourFormat) {
+            mFormat = SINGLE_LINE_FORMAT_12_HOUR;
+        } else {
+            mFormat = DOUBLE_LINE_FORMAT_12_HOUR;
+        }
+
         mDescFormat = getBestDateTimePattern(getContext(), use24HourFormat ? "Hm" : "hm");
         refreshTime();
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsController.java b/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsController.java
index 945c9c4..118f98d 100644
--- a/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsController.java
+++ b/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsController.java
@@ -154,7 +154,9 @@
                 @Override
                 public void onBiometricRunningStateChanged(boolean running,
                         BiometricSourceType biometricSourceType) {
-                    mRunningFPS = running && biometricSourceType == FINGERPRINT;
+                    if (biometricSourceType == FINGERPRINT) {
+                        mRunningFPS = running;
+                    }
                     mAuthenticated &= !mRunningFPS;
                     updateButtonVisibility();
                 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 93ed0ea..13a84fb 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -174,7 +174,7 @@
         if (mode == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1) {
             final int startEndPadding = (int) TypedValue.applyDimension(
                     TypedValue.COMPLEX_UNIT_DIP,
-                    12,
+                    32,
                     getResources().getDisplayMetrics());
             setPaddingRelative(startEndPadding, 0, startEndPadding, 0);
             mSmallClockFrame.setVisibility(GONE);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
index ea60f0d..72dd72e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
@@ -29,6 +29,7 @@
 import android.view.View;
 import android.view.View.OnKeyListener;
 import android.view.ViewTreeObserver;
+import android.widget.FrameLayout;
 
 import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback;
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
@@ -180,6 +181,7 @@
     /** Initialize the Controller. */
     public void onInit() {
         mKeyguardSecurityContainerController.init();
+        updateResources();
     }
 
     @Override
@@ -467,5 +469,23 @@
         mSecurityCallback.finish(strongAuth, currentUser);
     }
 
+    /**
+     * Apply keyguard configuration from the currently active resources. This can be called when the
+     * device configuration changes, to re-apply some resources that are qualified on the device
+     * configuration.
+     */
+    public void updateResources() {
+        int gravity = mView.getResources().getInteger(R.integer.keyguard_host_view_gravity);
 
+        // Android SysUI uses a FrameLayout as the top-level, but Auto uses RelativeLayout.
+        // We're just changing the gravity here though (which can't be applied to RelativeLayout),
+        // so only attempt the update if mView is inside a FrameLayout.
+        if (mView.getLayoutParams() instanceof FrameLayout.LayoutParams) {
+            FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mView.getLayoutParams();
+            if (lp.gravity != gravity) {
+                lp.gravity = gravity;
+                mView.setLayoutParams(lp);
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
index 4f48bb4..e16c01a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
@@ -109,7 +109,7 @@
                 // Treat single-sized patterns as erroneous taps.
                 if (pattern.size() == 1) {
                     mFalsingCollector.updateFalseConfidence(FalsingClassifier.Result.falsed(
-                            0.7, "empty pattern input"));
+                            0.7, getClass().getSimpleName(), "empty pattern input"));
                 }
                 mLockPatternView.enableInput();
                 onPatternChecked(userId, false, 0, false /* not valid - too short */);
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 1765627..cd53a34 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -326,6 +326,9 @@
         if (mBatteryPercentView != null) {
             if (mShowPercentMode == MODE_ESTIMATE && !mCharging) {
                 mBatteryController.getEstimatedTimeRemainingString((String estimate) -> {
+                    if (mBatteryPercentView == null) {
+                        return;
+                    }
                     if (estimate != null) {
                         mBatteryPercentView.setText(estimate);
                         setContentDescription(getContext().getString(
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index ae4c8e5..06b486e 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -34,6 +34,9 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.clock.ClockManager;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
+import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
+import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;
 import com.android.systemui.appops.AppOpsController;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -284,6 +287,8 @@
     @Inject Lazy<IWindowManager> mIWindowManager;
     @Inject Lazy<OverviewProxyService> mOverviewProxyService;
     @Inject Lazy<NavigationModeController> mNavBarModeController;
+    @Inject Lazy<AccessibilityButtonModeObserver> mAccessibilityButtonModeObserver;
+    @Inject Lazy<AccessibilityButtonTargetsObserver> mAccessibilityButtonListController;
     @Inject Lazy<EnhancedEstimates> mEnhancedEstimates;
     @Inject Lazy<VibratorHelper> mVibratorHelper;
     @Inject Lazy<IStatusBarService> mIStatusBarService;
@@ -294,6 +299,7 @@
     @Inject Lazy<NotificationRemoteInputManager.Callback> mNotificationRemoteInputManagerCallback;
     @Inject Lazy<AppOpsController> mAppOpsController;
     @Inject Lazy<NavigationBarController> mNavigationBarController;
+    @Inject Lazy<AccessibilityFloatingMenuController> mAccessibilityFloatingMenuController;
     @Inject Lazy<StatusBarStateController> mStatusBarStateController;
     @Inject Lazy<NotificationLockscreenUserManager> mNotificationLockscreenUserManager;
     @Inject Lazy<NotificationGroupAlertTransferHelper> mNotificationGroupAlertTransferHelper;
@@ -470,6 +476,11 @@
 
         mProviders.put(NavigationModeController.class, mNavBarModeController::get);
 
+        mProviders.put(AccessibilityButtonModeObserver.class,
+                mAccessibilityButtonModeObserver::get);
+        mProviders.put(AccessibilityButtonTargetsObserver.class,
+                mAccessibilityButtonListController::get);
+
         mProviders.put(EnhancedEstimates.class, mEnhancedEstimates::get);
 
         mProviders.put(VibratorHelper.class, mVibratorHelper::get);
@@ -489,6 +500,9 @@
 
         mProviders.put(NavigationBarController.class, mNavigationBarController::get);
 
+        mProviders.put(AccessibilityFloatingMenuController.class,
+                mAccessibilityFloatingMenuController::get);
+
         mProviders.put(StatusBarStateController.class, mStatusBarStateController::get);
         mProviders.put(NotificationLockscreenUserManager.class,
                 mNotificationLockscreenUserManager::get);
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 7966b38..8b68ae9 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -29,6 +29,7 @@
 import android.util.Log;
 import android.util.MathUtils;
 import android.util.Size;
+import android.view.Choreographer;
 import android.view.SurfaceHolder;
 import android.view.WindowManager;
 
@@ -37,6 +38,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.glwallpaper.EglHelper;
 import com.android.systemui.glwallpaper.ImageWallpaperRenderer;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -53,10 +55,11 @@
     private static final String TAG = ImageWallpaper.class.getSimpleName();
     // We delayed destroy render context that subsequent render requests have chance to cancel it.
     // This is to avoid destroying then recreating render context in a very short time.
-    private static final int DELAY_FINISH_RENDERING = 1000;
+    private static final int DELAY_FINISH_RENDERING = 3000;
     private static final @android.annotation.NonNull RectF LOCAL_COLOR_BOUNDS =
             new RectF(0, 0, 1, 1);
     private static final boolean DEBUG = false;
+    private final StatusBarStateController mStatusBarStateController;
     private final ArrayList<RectF> mLocalColorsToAdd = new ArrayList<>();
     private final ArraySet<RectF> mColorAreas = new ArraySet<>();
     private float mShift;
@@ -66,8 +69,9 @@
     private Bitmap mMiniBitmap;
 
     @Inject
-    public ImageWallpaper() {
+    public ImageWallpaper(StatusBarStateController statusBarStateController) {
         super();
+        mStatusBarStateController = statusBarStateController;
     }
 
     @Override
@@ -90,7 +94,9 @@
         mMiniBitmap = null;
     }
 
-    class GLEngine extends Engine {
+
+    class GLEngine extends Engine implements StatusBarStateController.StateListener,
+            Choreographer.FrameCallback {
         // Surface is rejected if size below a threshold on some devices (ie. 8px on elfin)
         // set min to 64 px (CTS covers this), please refer to ag/4867989 for detail.
         @VisibleForTesting
@@ -101,11 +107,12 @@
         private ImageWallpaperRenderer mRenderer;
         private EglHelper mEglHelper;
         private final Runnable mFinishRenderingTask = this::finishRendering;
-        private boolean mNeedRedraw;
         private int mWidth = 1;
         private int mHeight = 1;
         private int mImgWidth = 1;
         private int mImgHeight = 1;
+        private volatile float mDozeAmount;
+        private volatile boolean mNewDozeValue = false;
 
         GLEngine() {
         }
@@ -130,8 +137,14 @@
             mWidth = window.width();
             mMiniBitmap = null;
             if (mWorker != null && mWorker.getThreadHandler() != null) {
-                mWorker.getThreadHandler().post(this::updateMiniBitmap);
+                mWorker.getThreadHandler().post(() -> {
+                    updateMiniBitmap();
+                    Choreographer.getInstance().postFrameCallback(GLEngine.this);
+                });
             }
+
+            mDozeAmount = mStatusBarStateController.getDozeAmount();
+            mStatusBarStateController.addCallback(this);
         }
 
         EglHelper getEglHelperInstance() {
@@ -210,11 +223,14 @@
         public void onDestroy() {
             mMiniBitmap = null;
             mWorker.getThreadHandler().post(() -> {
+                Choreographer.getInstance().removeFrameCallback(this);
                 mRenderer.finish();
                 mRenderer = null;
                 mEglHelper.finish();
                 mEglHelper = null;
             });
+
+            mStatusBarStateController.removeCallback(this);
         }
 
         @Override
@@ -323,9 +339,16 @@
         @Override
         public void onSurfaceRedrawNeeded(SurfaceHolder holder) {
             if (mWorker == null) return;
+            mDozeAmount = mStatusBarStateController.getDozeAmount();
             mWorker.getThreadHandler().post(this::drawFrame);
         }
 
+        @Override
+        public void onDozeAmountChanged(float linear, float eased) {
+            mDozeAmount = linear;
+            mNewDozeValue = true;
+        }
+
         private void drawFrame() {
             preRender();
             requestRender();
@@ -381,6 +404,7 @@
                     && frame.width() > 0 && frame.height() > 0;
 
             if (readyToRender) {
+                mRenderer.setExposureValue(1 - mDozeAmount);
                 mRenderer.onDrawFrame();
                 if (!mEglHelper.swapBuffer()) {
                     Log.e(TAG, "drawFrame failed!");
@@ -438,5 +462,14 @@
             mEglHelper.dump(prefix, fd, out, args);
             mRenderer.dump(prefix, fd, out, args);
         }
+
+        @Override
+        public void doFrame(long frameTimeNanos) {
+            if (mNewDozeValue) {
+                drawFrame();
+                mNewDozeValue = false;
+            }
+            Choreographer.getInstance().postFrameCallback(this);
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index f210d50..f28d113 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -74,7 +74,7 @@
             Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP,
             Key.HAS_SEEN_REVERSE_BOTTOM_SHEET,
             Key.CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT,
-            Key.HAS_SEEN_PRIORITY_ONBOARDING
+            Key.HAS_SEEN_PRIORITY_ONBOARDING_IN_S
     })
     // TODO: annotate these with their types so {@link PrefsCommandLine} can know how to set them
     public @interface Key {
@@ -124,7 +124,7 @@
         String HAS_SEEN_REVERSE_BOTTOM_SHEET = "HasSeenReverseBottomSheet";
         String CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT = "ControlsStructureSwipeTooltipCount";
         /** Tracks whether the user has seen the onboarding screen for priority conversations */
-        String HAS_SEEN_PRIORITY_ONBOARDING = "HasUserSeenPriorityOnboarding";
+        String HAS_SEEN_PRIORITY_ONBOARDING_IN_S = "HasUserSeenPriorityOnboardingInS";
     }
 
     public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) {
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 59c0fb8..865ca40 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -19,18 +19,15 @@
 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;
@@ -40,8 +37,6 @@
 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;
 
@@ -126,26 +121,6 @@
                             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/accessibility/AccessibilityButtonModeObserver.java b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonModeObserver.java
new file mode 100644
index 0000000..9bedb1e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonModeObserver.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility;
+
+import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
+import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
+
+import android.annotation.IntDef;
+import android.annotation.MainThread;
+import android.content.Context;
+import android.provider.Settings;
+import android.util.Log;
+
+import com.android.systemui.dagger.SysUISingleton;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import javax.inject.Inject;
+
+/**
+ * Observes changes of the accessibility button mode
+ * {@link Settings.Secure#ACCESSIBILITY_BUTTON_MODE} and notify its listeners.
+ */
+@MainThread
+@SysUISingleton
+public class AccessibilityButtonModeObserver extends
+        SecureSettingsContentObserver<AccessibilityButtonModeObserver.ModeChangedListener> {
+
+    private static final String TAG = "A11yButtonModeObserver";
+
+    private static final int ACCESSIBILITY_BUTTON_MODE_DEFAULT =
+            ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR,
+            ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU
+    })
+    public @interface AccessibilityButtonMode {}
+
+    /** Listener for accessibility button mode changes. */
+    public interface ModeChangedListener {
+
+        /**
+         * Called when accessibility button mode changes.
+         *
+         * @param mode Current accessibility button mode
+         */
+        void onAccessibilityButtonModeChanged(@AccessibilityButtonMode int mode);
+    }
+
+    @Inject
+    public AccessibilityButtonModeObserver(Context context) {
+        super(context, Settings.Secure.ACCESSIBILITY_BUTTON_MODE);
+    }
+
+    @Override
+    void onValueChanged(ModeChangedListener listener, String value) {
+        final int mode = parseAccessibilityButtonMode(value);
+        listener.onAccessibilityButtonModeChanged(mode);
+    }
+
+    /**
+     * Gets the current accessibility button mode from the current user's settings.
+     *
+     * See {@link Settings.Secure#ACCESSIBILITY_BUTTON_MODE}.
+     */
+    public int getCurrentAccessibilityButtonMode() {
+        final String value = getSettingsValue();
+
+        return parseAccessibilityButtonMode(value);
+    }
+
+    private int parseAccessibilityButtonMode(String value) {
+        int mode;
+
+        try {
+            mode = Integer.parseInt(value);
+        } catch (NumberFormatException e) {
+            Log.e(TAG, "Invalid string for  " + e);
+            mode = ACCESSIBILITY_BUTTON_MODE_DEFAULT;
+        }
+
+        return mode;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonTargetsObserver.java b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonTargetsObserver.java
new file mode 100644
index 0000000..b32ebcc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonTargetsObserver.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 com.android.systemui.accessibility;
+
+import android.content.Context;
+import android.provider.Settings;
+
+import androidx.annotation.MainThread;
+import androidx.annotation.Nullable;
+
+import com.android.systemui.dagger.SysUISingleton;
+
+import javax.inject.Inject;
+
+/**
+ * Controller for tracking the current accessibility button list.
+ *
+ * @see Settings.Secure#ACCESSIBILITY_BUTTON_TARGETS
+ */
+@MainThread
+@SysUISingleton
+public class AccessibilityButtonTargetsObserver extends
+        SecureSettingsContentObserver<AccessibilityButtonTargetsObserver.TargetsChangedListener> {
+
+    /** Listener for accessibility button targets changes. */
+    public interface TargetsChangedListener {
+
+        /**
+         * Called when accessibility button targets changes.
+         *
+         * @param targets Current content of {@link Settings.Secure#ACCESSIBILITY_BUTTON_TARGETS}
+         */
+        void onAccessibilityButtonTargetsChanged(String targets);
+    }
+
+    @Inject
+    public AccessibilityButtonTargetsObserver(Context context) {
+        super(context, Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);
+    }
+
+    @Override
+    void onValueChanged(TargetsChangedListener listener, String value) {
+        listener.onAccessibilityButtonTargetsChanged(value);
+    }
+
+    /** Returns the current string from settings key
+     *  {@link Settings.Secure#ACCESSIBILITY_BUTTON_TARGETS}. */
+    @Nullable
+    public String getCurrentAccessibilityButtonTargets() {
+        return getSettingsValue();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
index c1cf8d3..9f77b7d 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
@@ -19,6 +19,7 @@
 import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
 
 import android.annotation.NonNull;
+import android.annotation.UiContext;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.graphics.PixelFormat;
@@ -69,7 +70,7 @@
     private final MagnificationGestureDetector mGestureDetector;
     private boolean mSingleTapDetected = false;
 
-    MagnificationModeSwitch(Context context) {
+    MagnificationModeSwitch(@UiContext Context context) {
         this(context, createView(context));
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/ModeSwitchesController.java b/packages/SystemUI/src/com/android/systemui/accessibility/ModeSwitchesController.java
index 50f6e9f..1a01ad8 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/ModeSwitchesController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/ModeSwitchesController.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.accessibility;
 
+import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
+
 import android.annotation.MainThread;
 import android.content.Context;
 import android.hardware.display.DisplayManager;
@@ -106,10 +108,9 @@
 
         @Override
         protected MagnificationModeSwitch createInstance(Display display) {
-            final Context context = (display.getDisplayId() == Display.DEFAULT_DISPLAY)
-                    ? mContext
-                    : mContext.createDisplayContext(display);
-            return new MagnificationModeSwitch(context);
+            final Context uiContext = mContext.createWindowContext(display,
+                    TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, /* options */ null);
+            return new MagnificationModeSwitch(uiContext);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SecureSettingsContentObserver.java b/packages/SystemUI/src/com/android/systemui/accessibility/SecureSettingsContentObserver.java
new file mode 100644
index 0000000..4f8d866
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/SecureSettingsContentObserver.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.Settings;
+
+import androidx.annotation.NonNull;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Provides basic methods for adding, removing arbitrary listeners and inquiry given {@code
+ * secureSettingsKey} value; it must comes from {@link Settings.Secure}.
+ *
+ * This abstract class is intended to be subclassed and specialized to maintain
+ * a registry of listeners of specific types and dispatch changes to them.
+ *
+ * @param <T> The listener type
+ */
+public abstract class SecureSettingsContentObserver<T> {
+
+    private final ContentResolver mContentResolver;
+    @VisibleForTesting
+    final ContentObserver mContentObserver;
+
+    private final String mKey;
+
+    @VisibleForTesting
+    final List<T> mListeners = new ArrayList<>();
+
+    protected SecureSettingsContentObserver(Context context, String secureSettingsKey) {
+        mKey = secureSettingsKey;
+        mContentResolver = context.getContentResolver();
+        mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
+            @Override
+            public void onChange(boolean selfChange) {
+                updateValueChanged();
+            }
+        };
+    }
+
+    /**
+     * Registers a listener to receive updates from given settings key {@code secureSettingsKey}.
+     *
+     * @param listener A listener to be added to receive the changes
+     */
+    public void addListener(@NonNull T listener) {
+        Objects.requireNonNull(listener, "listener must be non-null");
+
+        mListeners.add(listener);
+
+        if (mListeners.size() == 1) {
+            mContentResolver.registerContentObserver(
+                    Settings.Secure.getUriFor(mKey), /* notifyForDescendants= */
+                    false, mContentObserver);
+        }
+    }
+
+    /**
+     * Unregisters a listener previously registered with {@link #addListener(T listener)}.
+     *
+     * @param listener A listener to be removed from receiving the changes
+     */
+    public void removeListener(@NonNull T listener) {
+        Objects.requireNonNull(listener, "listener must be non-null");
+
+        mListeners.remove(listener);
+
+        if (mListeners.isEmpty()) {
+            mContentResolver.unregisterContentObserver(mContentObserver);
+        }
+    }
+
+    /**
+     * Gets the value from the current user's secure settings.
+     *
+     * See {@link Settings.Secure}.
+     */
+    public final String getSettingsValue() {
+        return Settings.Secure.getString(mContentResolver, mKey);
+    }
+
+    private void updateValueChanged() {
+        final String value = getSettingsValue();
+        final int listenerSize = mListeners.size();
+        for (int i = 0; i < listenerSize; i++) {
+            onValueChanged(mListeners.get(i), value);
+        }
+    }
+
+    /**
+     * Called when the registered value from {@code secureSettingsKey} changes.
+     *
+     * @param listener A listener could be used to receive the updates
+     * @param value Content changed value from {@code secureSettingsKey}
+     */
+    abstract void onValueChanged(T listener, String value);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
index c051b69..ca2c034 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
@@ -49,7 +49,6 @@
 import com.android.internal.R;
 import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity;
 import com.android.internal.util.ScreenshotHelper;
-import com.android.systemui.Dependency;
 import com.android.systemui.SystemUI;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.recents.Recents;
@@ -140,6 +139,7 @@
     private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
 
     private final SystemActionsBroadcastReceiver mReceiver;
+    private final Recents mRecents;
     private Locale mLocale;
     private final AccessibilityManager mA11yManager;
     private final Lazy<StatusBar> mStatusBar;
@@ -150,8 +150,10 @@
     @Inject
     public SystemActions(Context context,
             NotificationShadeWindowController notificationShadeController,
-            Lazy<StatusBar> statusBar) {
+            Lazy<StatusBar> statusBar,
+            Recents recents) {
         super(context);
+        mRecents = recents;
         mReceiver = new SystemActionsBroadcastReceiver();
         mLocale = mContext.getResources().getConfiguration().getLocales().get(0);
         mA11yManager = (AccessibilityManager) mContext.getSystemService(
@@ -366,15 +368,15 @@
     }
 
     private void handleRecents() {
-        Dependency.get(Recents.class).toggleRecentApps();
+        mRecents.toggleRecentApps();
     }
 
     private void handleNotifications() {
-        Dependency.get(StatusBar.class).animateExpandNotificationsPanel();
+        mStatusBar.get().animateExpandNotificationsPanel();
     }
 
     private void handleQuickSettings() {
-        Dependency.get(StatusBar.class).animateExpandSettingsPanel(null);
+        mStatusBar.get().animateExpandSettingsPanel(null);
     }
 
     private void handlePowerDialog() {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
index f52dcd5..cdd6942 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.accessibility;
 
+import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
+
 import android.annotation.MainThread;
 import android.annotation.Nullable;
 import android.content.Context;
@@ -82,9 +84,8 @@
 
         @Override
         protected WindowMagnificationAnimationController createInstance(Display display) {
-            final Context context = (display.getDisplayId() == Display.DEFAULT_DISPLAY)
-                    ? mContext
-                    : mContext.createDisplayContext(display);
+            final Context windowContext = mContext.createWindowContext(display,
+                    TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, /* options */ null);
             final WindowMagnificationController controller = new WindowMagnificationController(
                     mContext,
                     mHandler, new SfVsyncFrameCallbackProvider(), null,
@@ -92,7 +93,7 @@
             final int navBarMode = mNavigationModeController.addListener(
                     controller::onNavigationModeChanged);
             controller.onNavigationModeChanged(navBarMode);
-            return new WindowMagnificationAnimationController(context, controller);
+            return new WindowMagnificationAnimationController(windowContext, controller);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java
index 24d8388..5758b15 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java
@@ -20,6 +20,7 @@
 import android.animation.ValueAnimator;
 import android.annotation.IntDef;
 import android.annotation.Nullable;
+import android.annotation.UiContext;
 import android.content.Context;
 import android.content.res.Resources;
 import android.os.RemoteException;
@@ -69,8 +70,8 @@
     @MagnificationState
     private int mState = STATE_DISABLED;
 
-    WindowMagnificationAnimationController(
-            Context context, WindowMagnificationController controller) {
+    WindowMagnificationAnimationController(@UiContext Context context,
+            WindowMagnificationController controller) {
         this(context, controller, newValueAnimator(context.getResources()));
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 3f7d2d8..2b666f1 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -24,6 +24,7 @@
 import android.animation.PropertyValuesHolder;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UiContext;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.res.Resources;
@@ -134,7 +135,7 @@
     @Nullable
     private MirrorWindowControl mMirrorWindowControl;
 
-    WindowMagnificationController(Context context, @NonNull Handler handler,
+    WindowMagnificationController(@UiContext Context context, @NonNull Handler handler,
             SfVsyncFrameCallbackProvider sfVsyncFrameProvider,
             MirrorWindowControl mirrorWindowControl, SurfaceControl.Transaction transaction,
             @NonNull WindowMagnifierCallback callback) {
@@ -147,7 +148,7 @@
         mDisplayId = mContext.getDisplayId();
         mRotation = display.getRotation();
 
-        mWm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        mWm = context.getSystemService(WindowManager.class);
 
         mResources = mContext.getResources();
         mScale = mResources.getInteger(R.integer.magnification_default_scale);
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java
new file mode 100644
index 0000000..7b4ce61
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.floatingmenu;
+
+import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED;
+import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_ICON_TYPE;
+import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY;
+import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE;
+import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
+
+import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getTargets;
+import static com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuView.ShapeType;
+import static com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuView.SizeType;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Contains logic for an accessibility floating menu view.
+ */
+public class AccessibilityFloatingMenu implements IAccessibilityFloatingMenu {
+    private static final int DEFAULT_FADE_EFFECT_ENABLED = 1;
+    private static final float DEFAULT_OPACITY_VALUE = 0.55f;
+    private final Context mContext;
+    private final AccessibilityFloatingMenuView mMenuView;
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
+
+    private final ContentObserver mContentObserver =
+            new ContentObserver(mHandler) {
+                @Override
+                public void onChange(boolean selfChange) {
+                    mMenuView.onTargetsChanged(getTargets(mContext, ACCESSIBILITY_BUTTON));
+                }
+            };
+
+    private final ContentObserver mSizeContentObserver =
+            new ContentObserver(mHandler) {
+                @Override
+                public void onChange(boolean selfChange) {
+                    mMenuView.setSizeType(getSizeType(mContext));
+                }
+            };
+
+    private final ContentObserver mFadeOutContentObserver =
+            new ContentObserver(mHandler) {
+                @Override
+                public void onChange(boolean selfChange) {
+                    mMenuView.updateOpacityWith(isFadeEffectEnabled(mContext),
+                            getOpacityValue(mContext));
+                }
+            };
+
+    public AccessibilityFloatingMenu(Context context) {
+        mContext = context;
+        mMenuView = new AccessibilityFloatingMenuView(context);
+    }
+
+    @VisibleForTesting
+    AccessibilityFloatingMenu(Context context, AccessibilityFloatingMenuView menuView) {
+        mContext = context;
+        mMenuView = menuView;
+    }
+
+    @Override
+    public boolean isShowing() {
+        return mMenuView.isShowing();
+    }
+
+    @Override
+    public void show() {
+        if (isShowing()) {
+            return;
+        }
+
+        mMenuView.show();
+        mMenuView.onTargetsChanged(getTargets(mContext, ACCESSIBILITY_BUTTON));
+        mMenuView.updateOpacityWith(isFadeEffectEnabled(mContext),
+                getOpacityValue(mContext));
+        mMenuView.setSizeType(getSizeType(mContext));
+        mMenuView.setShapeType(getShapeType(mContext));
+
+        registerContentObservers();
+    }
+
+    @Override
+    public void hide() {
+        if (!isShowing()) {
+            return;
+        }
+
+        mMenuView.hide();
+
+        unregisterContentObservers();
+    }
+
+    private static boolean isFadeEffectEnabled(Context context) {
+        return Settings.Secure.getInt(
+                context.getContentResolver(), ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED,
+                DEFAULT_FADE_EFFECT_ENABLED) == /* enable */ 1;
+    }
+
+    private static float getOpacityValue(Context context) {
+        return Settings.Secure.getFloat(
+                context.getContentResolver(), ACCESSIBILITY_FLOATING_MENU_OPACITY,
+                DEFAULT_OPACITY_VALUE);
+    }
+
+    private static int getSizeType(Context context) {
+        return Settings.Secure.getInt(
+                context.getContentResolver(), ACCESSIBILITY_FLOATING_MENU_SIZE, SizeType.SMALL);
+    }
+
+    private static int getShapeType(Context context) {
+        return Settings.Secure.getInt(
+                context.getContentResolver(), ACCESSIBILITY_FLOATING_MENU_ICON_TYPE,
+                ShapeType.OVAL);
+    }
+
+    private void registerContentObservers() {
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS),
+                /* notifyForDescendants */ false, mContentObserver,
+                UserHandle.USER_CURRENT);
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE),
+                /* notifyForDescendants */ false, mSizeContentObserver,
+                UserHandle.USER_CURRENT);
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED),
+                /* notifyForDescendants */ false, mFadeOutContentObserver,
+                UserHandle.USER_CURRENT);
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY),
+                /* notifyForDescendants */ false, mFadeOutContentObserver,
+                UserHandle.USER_CURRENT);
+    }
+
+    private void unregisterContentObservers() {
+        mContext.getContentResolver().unregisterContentObserver(mContentObserver);
+        mContext.getContentResolver().unregisterContentObserver(mSizeContentObserver);
+        mContext.getContentResolver().unregisterContentObserver(mFadeOutContentObserver);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
new file mode 100644
index 0000000..112e9ca
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.floatingmenu;
+
+import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.view.accessibility.AccessibilityManager;
+
+import androidx.annotation.MainThread;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
+import com.android.systemui.accessibility.AccessibilityButtonModeObserver.AccessibilityButtonMode;
+import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
+import com.android.systemui.dagger.SysUISingleton;
+
+import javax.inject.Inject;
+
+/** A controller to handle the lifecycle of accessibility floating menu. */
+@MainThread
+@SysUISingleton
+public class AccessibilityFloatingMenuController implements
+        AccessibilityButtonModeObserver.ModeChangedListener,
+        AccessibilityButtonTargetsObserver.TargetsChangedListener,
+        AccessibilityManager.AccessibilityStateChangeListener {
+
+    private final Context mContext;
+    private final AccessibilityManager mAccessibilityManager;
+    private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
+    private final AccessibilityButtonTargetsObserver mAccessibilityButtonTargetsObserver;
+
+    @VisibleForTesting
+    IAccessibilityFloatingMenu mFloatingMenu;
+    private int mBtnMode;
+    private String mBtnTargets;
+
+    @Inject
+    public AccessibilityFloatingMenuController(Context context,
+            AccessibilityButtonTargetsObserver accessibilityButtonTargetsObserver,
+            AccessibilityButtonModeObserver accessibilityButtonModeObserver) {
+        mContext = context;
+        mAccessibilityButtonTargetsObserver = accessibilityButtonTargetsObserver;
+        mAccessibilityButtonModeObserver = accessibilityButtonModeObserver;
+        mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class);
+
+        mAccessibilityButtonModeObserver.addListener(this);
+        mAccessibilityButtonTargetsObserver.addListener(this);
+        mBtnMode = mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode();
+        mBtnTargets = mAccessibilityButtonTargetsObserver.getCurrentAccessibilityButtonTargets();
+
+        // Accessibility floating menu widget needs accessibility service to work, but system
+        // accessibility might be unavailable during the phone get booted, hence it needs to wait
+        // for accessibility manager callback to work.
+        mAccessibilityManager.addAccessibilityStateChangeListener(this);
+        if (mAccessibilityManager.isEnabled()) {
+            handleFloatingMenuVisibility(mBtnMode, mBtnTargets);
+            mAccessibilityManager.removeAccessibilityStateChangeListener(this);
+        }
+    }
+
+    /**
+     * Handles visibility of the accessibility floating menu when accessibility button mode changes.
+     *
+     * @param mode Current accessibility button mode.
+     */
+    @Override
+    public void onAccessibilityButtonModeChanged(@AccessibilityButtonMode int mode) {
+        mBtnMode = mode;
+        handleFloatingMenuVisibility(mBtnMode, mBtnTargets);
+    }
+
+    /**
+     * Handles visibility of the accessibility floating menu when accessibility button targets
+     * changes.
+     * List should come from {@link android.provider.Settings.Secure#ACCESSIBILITY_BUTTON_TARGETS}.
+     * @param targets Current accessibility button list.
+     */
+    @Override
+    public void onAccessibilityButtonTargetsChanged(String targets) {
+        mBtnTargets = targets;
+        handleFloatingMenuVisibility(mBtnMode, mBtnTargets);
+    }
+
+    /**
+     * Handles visibility of the accessibility floating menu when system accessibility state
+     * changes.
+     * If system accessibility become available onAccessibilityStateChanged(true), then we don't
+     * need to listen to this listener anymore.
+     *
+     * @param enabled Whether accessibility is enabled.
+     */
+    @Override
+    public void onAccessibilityStateChanged(boolean enabled) {
+        if (enabled) {
+            handleFloatingMenuVisibility(mBtnMode, mBtnTargets);
+        }
+
+        mAccessibilityManager.removeAccessibilityStateChangeListener(this);
+    }
+
+    private void handleFloatingMenuVisibility(@AccessibilityButtonMode int mode, String targets) {
+        if (shouldShowFloatingMenu(mode, targets)) {
+            showFloatingMenu();
+        } else {
+            destroyFloatingMenu();
+        }
+    }
+
+    private boolean shouldShowFloatingMenu(@AccessibilityButtonMode int mode, String targets) {
+        return mode == ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU && !TextUtils.isEmpty(targets);
+    }
+
+    private void showFloatingMenu() {
+        if (mFloatingMenu == null) {
+            mFloatingMenu = new AccessibilityFloatingMenu(mContext);
+        }
+
+        mFloatingMenu.show();
+    }
+
+    private void destroyFloatingMenu() {
+        if (mFloatingMenu == null) {
+            return;
+        }
+
+        mFloatingMenu.hide();
+        mFloatingMenu = null;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java
new file mode 100644
index 0000000..ab05c2a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java
@@ -0,0 +1,690 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.floatingmenu;
+
+import static android.util.MathUtils.constrain;
+import static android.util.MathUtils.sq;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.annotation.IntDef;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.LayerDrawable;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.DisplayMetrics;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.animation.OvershootInterpolator;
+import android.widget.FrameLayout;
+
+import androidx.annotation.DimenRes;
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.internal.accessibility.dialog.AccessibilityTarget;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.R;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Accessibility floating menu is used for the actions of accessibility features, it's also the
+ * action set.
+ *
+ * <p>The number of items would depend on strings key
+ * {@link android.provider.Settings.Secure#ACCESSIBILITY_BUTTON_TARGETS}.
+ */
+public class AccessibilityFloatingMenuView extends FrameLayout
+        implements RecyclerView.OnItemTouchListener {
+    private static final int INDEX_MENU_ITEM = 0;
+    private static final int FADE_OUT_DURATION_MS = 1000;
+    private static final int FADE_EFFECT_DURATION_MS = 3000;
+    private static final int SNAP_TO_LOCATION_DURATION_MS = 150;
+    private static final int MIN_WINDOW_X = 0;
+    private static final int MIN_WINDOW_Y = 0;
+    private static final float LOCATION_Y_PERCENTAGE = 0.8f;
+
+    private boolean mIsFadeEffectEnabled;
+    private boolean mIsShowing;
+    private boolean mIsDownInEnlargedTouchArea;
+    private boolean mIsDragging = false;
+    @Alignment
+    private int mAlignment = Alignment.RIGHT;
+    @SizeType
+    private int mSizeType = SizeType.SMALL;
+    @VisibleForTesting
+    @ShapeType
+    int mShapeType = ShapeType.OVAL;
+    private int mTemporaryShapeType;
+    @RadiusType
+    private int mRadiusType = RadiusType.LEFT_HALF_OVAL;
+    private int mMargin;
+    private int mPadding;
+    private int mScreenHeight;
+    private int mScreenWidth;
+    private int mIconWidth;
+    private int mIconHeight;
+    private int mInset;
+    private int mDownX;
+    private int mDownY;
+    private int mRelativeToPointerDownX;
+    private int mRelativeToPointerDownY;
+    private float mRadius;
+    private float mPercentageY = LOCATION_Y_PERCENTAGE;
+    private float mSquareScaledTouchSlop;
+    private final RecyclerView mListView;
+    private final AccessibilityTargetAdapter mAdapter;
+    private float mFadeOutValue;
+    private final ValueAnimator mFadeOutAnimator;
+    @VisibleForTesting
+    final ValueAnimator mDragAnimator;
+    private final Handler mUiHandler;
+    @VisibleForTesting
+    final WindowManager.LayoutParams mCurrentLayoutParams;
+    private final WindowManager mWindowManager;
+    private final List<AccessibilityTarget> mTargets = new ArrayList<>();
+
+    @IntDef({
+            SizeType.SMALL,
+            SizeType.LARGE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface SizeType {
+        int SMALL = 0;
+        int LARGE = 1;
+    }
+
+    @IntDef({
+            ShapeType.OVAL,
+            ShapeType.HALF_OVAL
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface ShapeType {
+        int OVAL = 0;
+        int HALF_OVAL = 1;
+    }
+
+    @IntDef({
+            RadiusType.LEFT_HALF_OVAL,
+            RadiusType.OVAL,
+            RadiusType.RIGHT_HALF_OVAL
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface RadiusType {
+        int LEFT_HALF_OVAL = 0;
+        int OVAL = 1;
+        int RIGHT_HALF_OVAL = 2;
+    }
+
+    @IntDef({
+            Alignment.LEFT,
+            Alignment.RIGHT
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface Alignment {
+        int LEFT = 0;
+        int RIGHT = 1;
+    }
+
+    public AccessibilityFloatingMenuView(Context context) {
+        this(context, new RecyclerView(context));
+    }
+
+    @VisibleForTesting
+    AccessibilityFloatingMenuView(Context context,
+            RecyclerView listView) {
+        super(context);
+
+        mListView = listView;
+        mWindowManager = context.getSystemService(WindowManager.class);
+        mCurrentLayoutParams = createDefaultLayoutParams();
+        mAdapter = new AccessibilityTargetAdapter(mTargets);
+        mUiHandler = createUiHandler();
+
+        mFadeOutAnimator = ValueAnimator.ofFloat(1.0f, mFadeOutValue);
+        mFadeOutAnimator.setDuration(FADE_OUT_DURATION_MS);
+        mFadeOutAnimator.addUpdateListener(
+                (animation) -> setAlpha((float) animation.getAnimatedValue()));
+
+        mDragAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
+        mDragAnimator.setDuration(SNAP_TO_LOCATION_DURATION_MS);
+        mDragAnimator.setInterpolator(new OvershootInterpolator());
+        mDragAnimator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mAlignment = calculateCurrentAlignment();
+                mPercentageY = calculateCurrentPercentageY();
+
+                updateLocationWith(mAlignment, mPercentageY);
+                updateMarginsWith(mAlignment);
+
+                updateInsetWith(getResources().getConfiguration().uiMode, mAlignment);
+
+                mRadiusType = (mAlignment == Alignment.RIGHT)
+                        ? RadiusType.LEFT_HALF_OVAL
+                        : RadiusType.RIGHT_HALF_OVAL;
+                updateRadiusWith(mSizeType, mRadiusType, mTargets.size());
+
+                fadeOut();
+            }
+        });
+
+        updateDimensions();
+        initListView();
+        updateStrokeWith(getResources().getConfiguration().uiMode, mAlignment);
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(@NonNull RecyclerView recyclerView,
+            @NonNull MotionEvent event) {
+        final int currentRawX = (int) event.getRawX();
+        final int currentRawY = (int) event.getRawY();
+
+        switch (event.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+                fadeIn();
+
+                mDownX = currentRawX;
+                mDownY = currentRawY;
+                mRelativeToPointerDownX = mCurrentLayoutParams.x - mDownX;
+                mRelativeToPointerDownY = mCurrentLayoutParams.y - mDownY;
+                mListView.animate().translationX(0);
+                break;
+            case MotionEvent.ACTION_MOVE:
+                if (mIsDragging
+                        || hasExceededTouchSlop(mDownX, mDownY, currentRawX, currentRawY)) {
+                    if (!mIsDragging) {
+                        mIsDragging = true;
+                        setRadius(mRadius, RadiusType.OVAL);
+                        setInset(0, 0);
+                    }
+
+                    mTemporaryShapeType =
+                            isMovingTowardsScreenEdge(mAlignment, currentRawX, mDownX)
+                                    ? ShapeType.HALF_OVAL
+                                    : ShapeType.OVAL;
+                    final int newWindowX = currentRawX + mRelativeToPointerDownX;
+                    final int newWindowY = currentRawY + mRelativeToPointerDownY;
+                    mCurrentLayoutParams.x = constrain(newWindowX, MIN_WINDOW_X, getMaxWindowX());
+                    mCurrentLayoutParams.y = constrain(newWindowY, MIN_WINDOW_Y, getMaxWindowY());
+                    mWindowManager.updateViewLayout(this, mCurrentLayoutParams);
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL:
+                if (mIsDragging) {
+                    mIsDragging = false;
+
+                    final int maxX = getMaxWindowX();
+                    final int endX = mCurrentLayoutParams.x > ((MIN_WINDOW_X + maxX) / 2)
+                            ? maxX : MIN_WINDOW_X;
+                    final int endY = mCurrentLayoutParams.y;
+                    snapToLocation(endX, endY);
+
+                    setShapeType(mTemporaryShapeType);
+
+                    // Avoid triggering the listener of the item.
+                    return true;
+                }
+
+                // Must switch the oval shape type before tapping the corresponding item in the
+                // list view, otherwise it can't work on it.
+                if (mShapeType == ShapeType.HALF_OVAL) {
+                    setShapeType(ShapeType.OVAL);
+
+                    return true;
+                }
+
+                fadeOut();
+                break;
+            default: // Do nothing
+        }
+
+        // not consume all the events here because keeping the scroll behavior of list view.
+        return false;
+    }
+
+    @Override
+    public void onTouchEvent(@NonNull RecyclerView recyclerView, @NonNull MotionEvent motionEvent) {
+        // Do Nothing
+    }
+
+    @Override
+    public void onRequestDisallowInterceptTouchEvent(boolean b) {
+        // Do Nothing
+    }
+
+    void show() {
+        if (isShowing()) {
+            return;
+        }
+
+        mIsShowing = true;
+        mWindowManager.addView(this, mCurrentLayoutParams);
+        setSystemGestureExclusion();
+    }
+
+    void hide() {
+        if (!isShowing()) {
+            return;
+        }
+
+        mIsShowing = false;
+        mWindowManager.removeView(this);
+        setSystemGestureExclusion();
+    }
+
+    boolean isShowing() {
+        return mIsShowing;
+    }
+
+    void onTargetsChanged(List<AccessibilityTarget> newTargets) {
+        fadeIn();
+
+        mTargets.clear();
+        mTargets.addAll(newTargets);
+        mAdapter.notifyDataSetChanged();
+
+        updateRadiusWith(mSizeType, mRadiusType, mTargets.size());
+        setSystemGestureExclusion();
+
+        fadeOut();
+    }
+
+    void setSizeType(@SizeType int newSizeType) {
+        fadeIn();
+
+        mSizeType = newSizeType;
+
+        updateIconSizeWith(newSizeType);
+        updateRadiusWith(newSizeType, mRadiusType, mTargets.size());
+
+        // When the icon sized changed, the menu size and location will be impacted.
+        updateLocationWith(mAlignment, mPercentageY);
+        setSystemGestureExclusion();
+
+        fadeOut();
+    }
+
+    void setShapeType(@ShapeType int newShapeType) {
+        fadeIn();
+
+        mShapeType = newShapeType;
+
+        updateOffsetWith(newShapeType, mAlignment);
+
+        setOnTouchListener(
+                newShapeType == ShapeType.OVAL
+                        ? null
+                        : (view, event) -> onTouched(event));
+
+        fadeOut();
+    }
+
+    void updateOpacityWith(boolean isFadeEffectEnabled, float newOpacityValue) {
+        mIsFadeEffectEnabled = isFadeEffectEnabled;
+        mFadeOutValue = newOpacityValue;
+
+        mFadeOutAnimator.cancel();
+        mFadeOutAnimator.setFloatValues(1.0f, mFadeOutValue);
+        setAlpha(mIsFadeEffectEnabled ? mFadeOutValue : /* completely opaque */ 1.0f);
+    }
+
+    @VisibleForTesting
+    void fadeIn() {
+        if (!mIsFadeEffectEnabled) {
+            return;
+        }
+
+        mFadeOutAnimator.cancel();
+        mUiHandler.removeCallbacksAndMessages(null);
+        mUiHandler.post(() -> setAlpha(/* completely opaque */ 1.0f));
+    }
+
+    @VisibleForTesting
+    void fadeOut() {
+        if (!mIsFadeEffectEnabled) {
+            return;
+        }
+
+        mUiHandler.postDelayed(() -> mFadeOutAnimator.start(), FADE_EFFECT_DURATION_MS);
+    }
+
+    private boolean onTouched(MotionEvent event) {
+        final int action = event.getAction();
+        final int currentX = (int) event.getX();
+        final int currentY = (int) event.getY();
+
+        final int menuHalfWidth = getLayoutWidth() / 2;
+        final Rect touchDelegateBounds =
+                new Rect(mMargin, mMargin, mMargin + menuHalfWidth, mMargin + getLayoutHeight());
+        if (action == MotionEvent.ACTION_DOWN
+                && touchDelegateBounds.contains(currentX, currentY)) {
+            mIsDownInEnlargedTouchArea = true;
+        }
+
+        if (!mIsDownInEnlargedTouchArea) {
+            return false;
+        }
+
+        if (action == MotionEvent.ACTION_UP
+                || action == MotionEvent.ACTION_CANCEL) {
+            mIsDownInEnlargedTouchArea = false;
+        }
+
+        // In order to correspond to the correct item of list view.
+        event.setLocation(currentX - mMargin, currentY - mMargin);
+        return mListView.dispatchTouchEvent(event);
+    }
+
+    private boolean isMovingTowardsScreenEdge(@Alignment int side, int currentRawX, int downX) {
+        return (side == Alignment.RIGHT && currentRawX > downX)
+                || (side == Alignment.LEFT && downX > currentRawX);
+    }
+
+    private boolean hasExceededTouchSlop(int startX, int startY, int endX, int endY) {
+        return (sq(endX - startX) + sq(endY - startY)) > mSquareScaledTouchSlop;
+    }
+
+    private void setRadius(float radius, @RadiusType int type) {
+        getMenuGradientDrawable().setCornerRadii(createRadii(radius, type));
+    }
+
+    private float[] createRadii(float radius, @RadiusType int type) {
+        if (type == RadiusType.LEFT_HALF_OVAL) {
+            return new float[]{radius, radius, 0.0f, 0.0f, 0.0f, 0.0f, radius, radius};
+        }
+
+        if (type == RadiusType.RIGHT_HALF_OVAL) {
+            return new float[]{0.0f, 0.0f, radius, radius, radius, radius, 0.0f, 0.0f};
+        }
+
+        return new float[]{radius, radius, radius, radius, radius, radius, radius, radius};
+    }
+
+    private Handler createUiHandler() {
+        final Looper looper = Looper.myLooper();
+        if (looper == null) {
+            throw new IllegalArgumentException("looper must not be null");
+        }
+        return new Handler(looper);
+    }
+
+    private void updateDimensions() {
+        final Resources res = getResources();
+        final DisplayMetrics dm = res.getDisplayMetrics();
+        mScreenWidth = dm.widthPixels;
+        mScreenHeight = dm.heightPixels;
+        mMargin =
+                res.getDimensionPixelSize(R.dimen.accessibility_floating_menu_margin);
+        mPadding =
+                res.getDimensionPixelSize(R.dimen.accessibility_floating_menu_padding);
+        mInset =
+                res.getDimensionPixelSize(R.dimen.accessibility_floating_menu_stroke_inset);
+
+        mSquareScaledTouchSlop =
+                sq(ViewConfiguration.get(getContext()).getScaledTouchSlop());
+    }
+
+    private void updateIconSizeWith(@SizeType int sizeType) {
+        final Resources res = getResources();
+        final int iconResId =
+                sizeType == SizeType.SMALL
+                        ? R.dimen.accessibility_floating_menu_small_width_height
+                        : R.dimen.accessibility_floating_menu_large_width_height;
+        mIconWidth = res.getDimensionPixelSize(iconResId);
+        mIconHeight = mIconWidth;
+
+        mAdapter.setIconWidthHeight(mIconWidth);
+        mAdapter.notifyDataSetChanged();
+    }
+
+    private void initListView() {
+        final Drawable background =
+                getContext().getDrawable(R.drawable.accessibility_floating_menu_background);
+        final LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
+        final LayoutParams layoutParams =
+                new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+                        ViewGroup.LayoutParams.WRAP_CONTENT);
+        mListView.setLayoutParams(layoutParams);
+        final InstantInsetLayerDrawable layerDrawable =
+                new InstantInsetLayerDrawable(new Drawable[]{background});
+        mListView.setBackground(layerDrawable);
+        mListView.setAdapter(mAdapter);
+        mListView.setLayoutManager(layoutManager);
+        mListView.addOnItemTouchListener(this);
+        mListView.animate().setInterpolator(new OvershootInterpolator());
+        updateListView();
+
+        addView(mListView);
+    }
+
+    private void updateListView() {
+        final int elevation =
+                getResources().getDimensionPixelSize(R.dimen.accessibility_floating_menu_elevation);
+        mListView.setElevation(elevation);
+
+        updateMarginsWith(mAlignment);
+    }
+
+    private WindowManager.LayoutParams createDefaultLayoutParams() {
+        final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
+                WindowManager.LayoutParams.WRAP_CONTENT,
+                WindowManager.LayoutParams.WRAP_CONTENT,
+                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+                PixelFormat.TRANSLUCENT);
+        params.windowAnimations = android.R.style.Animation_Translucent;
+        params.gravity = Gravity.START | Gravity.TOP;
+        params.x = getMaxWindowX();
+        params.y = (int) (getMaxWindowY() * mPercentageY);
+
+        return params;
+    }
+
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+
+        updateDimensions();
+        updateListView();
+        updateIconSizeWith(mSizeType);
+        updateColor();
+        updateStrokeWith(newConfig.uiMode, mAlignment);
+        updateLocationWith(mAlignment, mPercentageY);
+    }
+
+    private void snapToLocation(int endX, int endY) {
+        mDragAnimator.cancel();
+        mDragAnimator.removeAllUpdateListeners();
+        mDragAnimator.addUpdateListener(anim -> onDragAnimationUpdate(anim, endX, endY));
+        mDragAnimator.start();
+    }
+
+    private void onDragAnimationUpdate(ValueAnimator animator, int endX, int endY) {
+        float value = (float) animator.getAnimatedValue();
+        final int newX = (int) (((1 - value) * mCurrentLayoutParams.x) + (value * endX));
+        final int newY = (int) (((1 - value) * mCurrentLayoutParams.y) + (value * endY));
+
+        mCurrentLayoutParams.x = newX;
+        mCurrentLayoutParams.y = newY;
+        mWindowManager.updateViewLayout(this, mCurrentLayoutParams);
+    }
+
+    private int getMaxWindowX() {
+        return mScreenWidth - mMargin - getLayoutWidth();
+    }
+
+    private int getMaxWindowY() {
+        return mScreenHeight - getWindowHeight();
+    }
+
+    private InstantInsetLayerDrawable getMenuLayerDrawable() {
+        return (InstantInsetLayerDrawable) mListView.getBackground();
+    }
+
+    private GradientDrawable getMenuGradientDrawable() {
+        return (GradientDrawable) getMenuLayerDrawable().getDrawable(INDEX_MENU_ITEM);
+    }
+
+    /**
+     * Updates the floating menu to be fixed at the side of the screen.
+     */
+    private void updateLocationWith(@Alignment int side, float percentageCurrentY) {
+        mCurrentLayoutParams.x = (side == Alignment.RIGHT) ? getMaxWindowX() : MIN_WINDOW_X;
+        mCurrentLayoutParams.y = (int) (percentageCurrentY * getMaxWindowY());
+        mWindowManager.updateViewLayout(this, mCurrentLayoutParams);
+    }
+
+    private void updateOffsetWith(@ShapeType int shapeType, @Alignment int side) {
+        final float halfWidth = getLayoutWidth() / 2.0f;
+        final float offset = (shapeType == ShapeType.OVAL) ? 0 : halfWidth;
+        mListView.animate().translationX(side == Alignment.RIGHT ? offset : -offset);
+    }
+
+    private void updateMarginsWith(@Alignment int side) {
+        final LayoutParams layoutParams = (LayoutParams) mListView.getLayoutParams();
+        final int marginLeft = (side == Alignment.LEFT) ? 0 : mMargin;
+        final int marginRight = (side == Alignment.RIGHT) ? 0 : mMargin;
+
+        if (marginLeft == layoutParams.leftMargin
+                && marginRight == layoutParams.rightMargin) {
+            return;
+        }
+
+        layoutParams.setMargins(marginLeft, mMargin, marginRight, mMargin);
+        mListView.setLayoutParams(layoutParams);
+    }
+
+    private void updateColor() {
+        final int menuColorResId = R.color.accessibility_floating_menu_background;
+        getMenuGradientDrawable().setColor(getResources().getColor(menuColorResId));
+    }
+
+    private void updateStrokeWith(int uiMode, @Alignment int side) {
+        updateInsetWith(uiMode, side);
+
+        final boolean isNightMode =
+                (uiMode & Configuration.UI_MODE_NIGHT_MASK)
+                        == Configuration.UI_MODE_NIGHT_YES;
+        final Resources res = getResources();
+        final int width =
+                res.getDimensionPixelSize(R.dimen.accessibility_floating_menu_stroke_width);
+        final int strokeWidth = isNightMode ? width : 0;
+        final int strokeColor = res.getColor(R.color.accessibility_floating_menu_stroke_dark);
+        getMenuGradientDrawable().setStroke(strokeWidth, strokeColor);
+    }
+
+    private void updateRadiusWith(@SizeType int sizeType, @RadiusType int radiusType,
+            int itemCount) {
+        mRadius =
+                getResources().getDimensionPixelSize(getRadiusResId(sizeType, itemCount));
+        setRadius(mRadius, radiusType);
+    }
+
+    private void updateInsetWith(int uiMode, @Alignment int side) {
+        final boolean isNightMode =
+                (uiMode & Configuration.UI_MODE_NIGHT_MASK)
+                        == Configuration.UI_MODE_NIGHT_YES;
+
+        final int layerInset = isNightMode ? mInset : 0;
+        final int insetLeft = (side == Alignment.LEFT) ? layerInset : 0;
+        final int insetRight = (side == Alignment.RIGHT) ? layerInset : 0;
+        setInset(insetLeft, insetRight);
+    }
+
+    private void setInset(int left, int right) {
+        final LayerDrawable layerDrawable = getMenuLayerDrawable();
+        if (layerDrawable.getLayerInsetLeft(INDEX_MENU_ITEM) == left
+                && layerDrawable.getLayerInsetRight(INDEX_MENU_ITEM) == right) {
+            return;
+        }
+
+        layerDrawable.setLayerInset(INDEX_MENU_ITEM, left, 0, right, 0);
+    }
+
+    @Alignment
+    private int calculateCurrentAlignment() {
+        return mCurrentLayoutParams.x >= ((MIN_WINDOW_X + getMaxWindowX()) / 2)
+                ? Alignment.RIGHT
+                : Alignment.LEFT;
+    }
+
+    private float calculateCurrentPercentageY() {
+        return mCurrentLayoutParams.y / (float) getMaxWindowY();
+    }
+
+    private @DimenRes int getRadiusResId(@SizeType int sizeType, int itemCount) {
+        return sizeType == SizeType.SMALL
+                ? getSmallSizeResIdWith(itemCount)
+                : getLargeSizeResIdWith(itemCount);
+    }
+
+    private int getSmallSizeResIdWith(int itemCount) {
+        return itemCount > 1
+                ? R.dimen.accessibility_floating_menu_small_multiple_radius
+                : R.dimen.accessibility_floating_menu_small_single_radius;
+    }
+
+    private int getLargeSizeResIdWith(int itemCount) {
+        return itemCount > 1
+                ? R.dimen.accessibility_floating_menu_large_multiple_radius
+                : R.dimen.accessibility_floating_menu_large_single_radius;
+    }
+
+    private int getLayoutWidth() {
+        return mPadding * 2 + mIconWidth;
+    }
+
+    private int getLayoutHeight() {
+        return Math.min(mScreenHeight - mMargin * 2,
+                (mPadding + mIconHeight) * mTargets.size() + mPadding);
+    }
+
+    private int getWindowWidth() {
+        return mMargin + getLayoutWidth();
+    }
+
+    private int getWindowHeight() {
+        return Math.min(mScreenHeight, mMargin * 2 + getLayoutHeight());
+    }
+
+    private void setSystemGestureExclusion() {
+        final Rect excludeZone =
+                new Rect(0, 0, getWindowWidth(), getWindowHeight());
+        post(() -> setSystemGestureExclusionRects(
+                mIsShowing
+                        ? Collections.singletonList(excludeZone)
+                        : Collections.emptyList()));
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityTargetAdapter.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityTargetAdapter.java
new file mode 100644
index 0000000..bb4038e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityTargetAdapter.java
@@ -0,0 +1,150 @@
+/*
+ * 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.systemui.accessibility.floatingmenu;
+
+import static android.view.View.GONE;
+
+import static com.android.systemui.accessibility.floatingmenu.AccessibilityTargetAdapter.ItemType.FIRST_ITEM;
+import static com.android.systemui.accessibility.floatingmenu.AccessibilityTargetAdapter.ItemType.LAST_ITEM;
+import static com.android.systemui.accessibility.floatingmenu.AccessibilityTargetAdapter.ItemType.REGULAR_ITEM;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.RecyclerView.Adapter;
+
+import com.android.internal.accessibility.dialog.AccessibilityTarget;
+import com.android.systemui.R;
+import com.android.systemui.accessibility.floatingmenu.AccessibilityTargetAdapter.ViewHolder;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+
+/**
+ * An adapter which shows the set of accessibility targets that can be performed.
+ */
+public class AccessibilityTargetAdapter extends Adapter<ViewHolder> {
+    private int mIconWidthHeight;
+    private final List<AccessibilityTarget> mTargets;
+
+    @IntDef({
+            FIRST_ITEM,
+            REGULAR_ITEM,
+            LAST_ITEM
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface ItemType {
+        int FIRST_ITEM = 0;
+        int REGULAR_ITEM = 1;
+        int LAST_ITEM = 2;
+    }
+
+    public AccessibilityTargetAdapter(List<AccessibilityTarget> targets) {
+        mTargets = targets;
+    }
+
+    @NonNull
+    @Override
+    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, @ItemType int itemType) {
+        final View root = LayoutInflater.from(parent.getContext()).inflate(
+                R.layout.accessibility_floating_menu_item, parent,
+                /* attachToRoot= */ false);
+
+        if (itemType == FIRST_ITEM) {
+            return new TopViewHolder(root);
+        }
+
+        if (itemType == LAST_ITEM) {
+            return new BottomViewHolder(root);
+        }
+
+        return new ViewHolder(root);
+    }
+
+    @Override
+    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
+        holder.mIconView.setBackground(mTargets.get(position).getIcon());
+        holder.updateIconWidthHeight(mIconWidthHeight);
+        holder.itemView.setOnClickListener((v) -> mTargets.get(position).onSelected());
+    }
+
+    @ItemType
+    @Override
+    public int getItemViewType(int position) {
+        if (position == 0) {
+            return FIRST_ITEM;
+        }
+
+        if (position == (getItemCount() - 1)) {
+            return LAST_ITEM;
+        }
+
+        return REGULAR_ITEM;
+    }
+
+    @Override
+    public int getItemCount() {
+        return mTargets.size();
+    }
+
+    public void setIconWidthHeight(int iconWidthHeight) {
+        mIconWidthHeight = iconWidthHeight;
+    }
+
+    static class ViewHolder extends RecyclerView.ViewHolder {
+        final View mIconView;
+        final View mDivider;
+
+        ViewHolder(View itemView) {
+            super(itemView);
+            mIconView = itemView.findViewById(R.id.icon_view);
+            mDivider = itemView.findViewById(R.id.transparent_divider);
+        }
+
+        void updateIconWidthHeight(int newValue) {
+            final ViewGroup.LayoutParams layoutParams = mIconView.getLayoutParams();
+            if (layoutParams.width == newValue) {
+                return;
+            }
+            layoutParams.width = newValue;
+            layoutParams.height = newValue;
+            mIconView.setLayoutParams(layoutParams);
+        }
+    }
+
+    static class TopViewHolder extends ViewHolder {
+        TopViewHolder(View itemView) {
+            super(itemView);
+            final int padding = itemView.getPaddingStart();
+            itemView.setPaddingRelative(padding, padding, padding, 0);
+        }
+    }
+
+    static class BottomViewHolder extends ViewHolder {
+        BottomViewHolder(View itemView) {
+            super(itemView);
+            mDivider.setVisibility(GONE);
+            final int padding = itemView.getPaddingStart();
+            itemView.setPaddingRelative(padding, 0, padding, padding);
+        }
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/IAccessibilityFloatingMenu.java
similarity index 60%
copy from packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl
copy to packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/IAccessibilityFloatingMenu.java
index 54242be..62f02a0 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/IAccessibilityFloatingMenu.java
@@ -14,12 +14,25 @@
  * limitations under the License.
  */
 
-package com.android.systemui.shared.recents;
+package com.android.systemui.accessibility.floatingmenu;
 
 /**
- * Listener interface that Launcher attaches to SystemUI to get split-screen callbacks.
+ * Interface for managing the accessibility targets menu component.
  */
-oneway interface ISplitScreenListener {
-    void onStagePositionChanged(int stage, int position);
-    void onTaskStageChanged(int taskId, int stage, boolean visible);
+public interface IAccessibilityFloatingMenu {
+
+    /**
+     * Checks if the menu was shown.
+     */
+    boolean isShowing();
+
+    /**
+     * Shows the accessibility targets menu.
+     */
+    void show();
+
+    /**
+     * Hides the accessibility targets menu.
+     */
+    void hide();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/InstantInsetLayerDrawable.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/InstantInsetLayerDrawable.java
new file mode 100644
index 0000000..6c021a6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/InstantInsetLayerDrawable.java
@@ -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.systemui.accessibility.floatingmenu;
+
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+
+/**
+ * A drawable that forces to update the bounds {@link #onBoundsChange(Rect)} immediately after
+ * {@link #setLayerInset} dynamically.
+ */
+public class InstantInsetLayerDrawable extends LayerDrawable {
+    public InstantInsetLayerDrawable(Drawable[] layers) {
+        super(layers);
+    }
+
+    @Override
+    public void setLayerInset(int index, int l, int t, int r, int b) {
+        super.setLayerInset(index, l, t, r, b);
+        onBoundsChange(getBounds());
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/HbmCallback.java b/packages/SystemUI/src/com/android/systemui/biometrics/HbmCallback.java
index 2083f2e..d90d0f8 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/HbmCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/HbmCallback.java
@@ -16,9 +16,11 @@
 
 package com.android.systemui.biometrics;
 
-import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.view.Surface;
 
+import com.android.systemui.biometrics.HbmTypes.HbmType;
+
 /**
  * Interface for controlling the high-brightness mode (HBM). UdfpsView can use this callback to
  * enable the HBM while showing the fingerprint illumination, and to disable the HBM after the
@@ -26,16 +28,20 @@
  */
 public interface HbmCallback {
     /**
-     * UdfpsView will call this to enable the HBM before drawing the illumination dot.
+     * UdfpsView will call this to enable the HBM when the fingerprint illumination is needed.
      *
-     * @param surface A valid surface for which the HBM should be enabled.
+     * @param hbmType The type of HBM that should be enabled. See {@link HbmTypes}.
+     * @param surface The surface for which the HBM is requested, in case the HBM implementation
+     *                needs to set special surface flags to enable the HBM. Can be null.
      */
-    void enableHbm(@NonNull Surface surface);
+    void enableHbm(@HbmType int hbmType, @Nullable Surface surface);
 
     /**
      * UdfpsView will call this to disable the HBM when the illumination is not longer needed.
      *
-     * @param surface A valid surface for which the HBM should be disabled.
+     * @param hbmType The type of HBM that should be disabled. See {@link HbmTypes}.
+     * @param surface The surface for which the HBM is requested, in case the HBM implementation
+     *                needs to unset special surface flags to disable the HBM. Can be null.
      */
-    void disableHbm(@NonNull Surface surface);
+    void disableHbm(@HbmType int hbmType, @Nullable Surface surface);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/HbmTypes.java b/packages/SystemUI/src/com/android/systemui/biometrics/HbmTypes.java
new file mode 100644
index 0000000..96ee0f7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/HbmTypes.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.systemui.biometrics;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Different high-brightness mode (HBM) types that are relevant to this package.
+ */
+public final class HbmTypes {
+    /** HBM that applies to the whole screen. */
+    public static final int GLOBAL_HBM = 0;
+
+    /** HBM that only applies to a portion of the screen. */
+    public static final int LOCAL_HBM = 1;
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({GLOBAL_HBM, LOCAL_HBM})
+    public @interface HbmType {
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java
index b7726f4..2f025f6 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java
@@ -72,7 +72,7 @@
         mStateListener.onStateChanged(mStatusBarStateController.getState());
         mStatusBar.addExpansionChangedListener(mStatusBarExpansionChangedListener);
 
-        mDumpManger.registerDumpable(getTag(), this);
+        mDumpManger.registerDumpable(getDumpTag(), this);
     }
 
     @Override
@@ -80,7 +80,17 @@
         mStatusBarStateController.removeCallback(mStateListener);
         mStatusBar.removeExpansionChangedListener(mStatusBarExpansionChangedListener);
 
-        mDumpManger.unregisterDumpable(getTag());
+        mDumpManger.unregisterDumpable(getDumpTag());
+    }
+
+    /**
+     * in some cases, onViewAttached is called for the newly added view using an instance of
+     * this controller before onViewDetached is called on the previous view, so we must have a
+     * unique dump tag per instance of this class
+     * @return a unique tag for this instance of this class
+     */
+    private String getDumpTag() {
+        return getTag() + " (" + this + ")";
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 797a441..98b3fe4 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -19,6 +19,8 @@
 import static com.android.internal.util.Preconditions.checkArgument;
 import static com.android.internal.util.Preconditions.checkNotNull;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SuppressLint;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -42,11 +44,9 @@
 import android.view.VelocityTracker;
 import android.view.WindowManager;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.R;
+import com.android.systemui.biometrics.HbmTypes.HbmType;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.doze.DozeReceiver;
@@ -95,7 +95,7 @@
     // Tracks the velocity of a touch to help filter out the touches that move too fast.
     @Nullable private VelocityTracker mVelocityTracker;
     // The ID of the pointer for which ACTION_DOWN has occurred. -1 means no pointer is active.
-    private int mActivePointerId;
+    private int mActivePointerId = -1;
     // The timestamp of the most recent touch log.
     private long mTouchLogTime;
 
@@ -321,6 +321,7 @@
         mSensorProps = findFirstUdfps();
         // At least one UDFPS sensor exists
         checkArgument(mSensorProps != null);
+        mStatusBar.setSensorRect(getSensorLocation());
 
         mCoreLayoutParams = new WindowManager.LayoutParams(
                 // TODO(b/152419866): Use the UDFPS window type when it becomes available.
@@ -367,7 +368,8 @@
      */
     public RectF getSensorLocation() {
         // 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
+        // on lockscreen and for the udfps light reveal animation on keyguard.
+        // 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,
@@ -580,13 +582,13 @@
     }
 
     @Override
-    public void enableHbm(@NonNull Surface surface) {
+    public void enableHbm(@HbmType int hbmType, @Nullable Surface surface) {
         // Do nothing. This method can be implemented for devices that require the high-brightness
         // mode for fingerprint illumination.
     }
 
     @Override
-    public void disableHbm(@NonNull Surface surface) {
+    public void disableHbm(@HbmType int hbmType, @Nullable Surface surface) {
         // Do nothing. This method can be implemented for devices that require the high-brightness
         // mode for fingerprint illumination.
     }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsSurfaceView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsSurfaceView.java
index 61ec127..4d441bd 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsSurfaceView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsSurfaceView.java
@@ -23,16 +23,25 @@
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
 import android.graphics.RectF;
+import android.os.Build;
+import android.os.UserHandle;
+import android.provider.Settings;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 
+import com.android.systemui.biometrics.HbmTypes.HbmType;
+
 /**
  * Under-display fingerprint sensor Surface View. The surface should be used for HBM-specific things
  * only. All other animations should be done on the other view.
  */
 public class UdfpsSurfaceView extends SurfaceView implements UdfpsIlluminator {
     private static final String TAG = "UdfpsSurfaceView";
+    private static final String SETTING_HBM_TYPE =
+            "com.android.systemui.biometrics.UdfpsSurfaceView.hbmType";
+    private static final @HbmType int DEFAULT_HBM_TYPE = HbmTypes.GLOBAL_HBM;
 
     /**
      * This is used instead of {@link android.graphics.drawable.Drawable}, because the latter has
@@ -45,6 +54,7 @@
     @NonNull private final SurfaceHolder mHolder;
     @NonNull private final Paint mSensorPaint;
     @NonNull private final SimpleDrawable mIlluminationDotDrawable;
+    private final @HbmType int mHbmType;
 
     @NonNull private RectF mSensorRect;
     @Nullable private HbmCallback mHbmCallback;
@@ -70,6 +80,13 @@
         mIlluminationDotDrawable = canvas -> {
             canvas.drawOval(mSensorRect, mSensorPaint);
         };
+
+        if (Build.IS_ENG || Build.IS_USERDEBUG) {
+            mHbmType = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                    SETTING_HBM_TYPE, DEFAULT_HBM_TYPE, UserHandle.USER_CURRENT);
+        } else {
+            mHbmType = DEFAULT_HBM_TYPE;
+        }
     }
 
     @Override
@@ -79,10 +96,15 @@
 
     @Override
     public void startIllumination(@Nullable Runnable onIlluminatedRunnable) {
-        if (mHbmCallback != null && mHolder.getSurface().isValid()) {
-            mHbmCallback.enableHbm(mHolder.getSurface());
+        if (mHbmCallback != null) {
+            mHbmCallback.enableHbm(mHbmType, mHolder.getSurface());
+        } else {
+            Log.e(TAG, "startIllumination | mHbmCallback is null");
         }
-        drawImmediately(mIlluminationDotDrawable);
+
+        if (mHbmType == HbmTypes.GLOBAL_HBM) {
+            drawImmediately(mIlluminationDotDrawable);
+        }
 
         if (onIlluminatedRunnable != null) {
             // No framework API can reliably tell when a frame reaches the panel. A timeout is the
@@ -94,8 +116,10 @@
 
     @Override
     public void stopIllumination() {
-        if (mHbmCallback != null && mHolder.getSurface().isValid()) {
-            mHbmCallback.disableHbm(mHolder.getSurface());
+        if (mHbmCallback != null) {
+            mHbmCallback.disableHbm(mHbmType, mHolder.getSurface());
+        } else {
+            Log.e(TAG, "stopIllumination | mHbmCallback is null");
         }
 
         invalidate();
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
index 292af3f..7e7cdce 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
@@ -42,7 +42,6 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
-import java.util.Locale;
 import java.util.Queue;
 import java.util.Set;
 import java.util.StringJoiner;
@@ -94,9 +93,17 @@
         }
     };
 
-    private final BeliefListener mBeliefListener = belief -> {
-        if (belief > FALSE_BELIEF_THRESHOLD) {
-            mFalsingBeliefListeners.forEach(FalsingBeliefListener::onFalse);
+    private final BeliefListener mBeliefListener = new BeliefListener() {
+        @Override
+        public void onBeliefChanged(double belief) {
+            logInfo(String.format(
+                    "{belief=%s confidence=%s}",
+                    mHistoryTracker.falseBelief(),
+                    mHistoryTracker.falseConfidence()));
+            if (belief > FALSE_BELIEF_THRESHOLD) {
+                mFalsingBeliefListeners.forEach(FalsingBeliefListener::onFalse);
+                logInfo("Triggering False Event (Threshold: " + FALSE_BELIEF_THRESHOLD + ")");
+            }
         }
     };
 
@@ -105,13 +112,23 @@
                 @Override
                 public void onGestureComplete(long completionTimeMs) {
                     if (mPriorResults != null) {
+                        mPriorResults.forEach(result -> {
+                            if (result.isFalse()) {
+                                String reason = result.getReason();
+                                if (reason != null) {
+                                    logInfo(reason);
+                                }
+                            }
+                        });
+
                         mHistoryTracker.addResults(mPriorResults, completionTimeMs);
                         mPriorResults = null;
                     } else {
                         // Gestures that were not classified get treated as a false.
                         mHistoryTracker.addResults(
                                 Collections.singleton(
-                                        FalsingClassifier.Result.falsed(.8, "unclassified")),
+                                        FalsingClassifier.Result.falsed(
+                                                .8, getClass().getSimpleName(), "unclassified")),
                                 completionTimeMs);
                     }
                 }
@@ -154,30 +171,13 @@
 
         boolean result;
 
-        mDataProvider.setInteractionType(interactionType);
-
         if (!mTestHarness && !mDataProvider.isJustUnlockedWithFace() && !mDockManager.isDocked()) {
             Stream<FalsingClassifier.Result> results =
-                    mClassifiers.stream().map(falsingClassifier -> {
-                        FalsingClassifier.Result classifierResult =
-                                falsingClassifier.classifyGesture(
-                                        mHistoryTracker.falseBelief(),
-                                        mHistoryTracker.falseConfidence());
-                        if (classifierResult.isFalse()) {
-                            logInfo(String.format(
-                                    (Locale) null,
-                                    "{classifier=%s, interactionType=%d}",
-                                    falsingClassifier.getClass().getName(),
-                                    mDataProvider.getInteractionType()));
-                            String reason = classifierResult.getReason();
-                            if (reason != null) {
-                                logInfo(reason);
-                            }
-                        } else {
-                            logDebug(falsingClassifier.getClass().getName() + ": false");
-                        }
-                        return classifierResult;
-                    });
+                    mClassifiers.stream().map(falsingClassifier ->
+                            falsingClassifier.classifyGesture(
+                                    interactionType,
+                                    mHistoryTracker.falseBelief(),
+                                    mHistoryTracker.falseConfidence()));
             mPriorResults = new ArrayList<>();
             final boolean[] localResult = {false};
             results.forEach(classifierResult -> {
@@ -190,13 +190,13 @@
             mPriorResults = Collections.singleton(FalsingClassifier.Result.passed(1));
         }
 
-        logDebug("Is false touch? " + result);
+        logDebug("False Gesture: " + result);
 
         if (Build.IS_ENG || Build.IS_USERDEBUG) {
             // Copy motion events, as the passed in list gets emptied out elsewhere in the code.
             RECENT_SWIPES.add(new DebugSwipeRecord(
                     result,
-                    mDataProvider.getInteractionType(),
+                    interactionType,
                     mDataProvider.getRecentMotionEvents().stream().map(
                             motionEvent -> new XYDt(
                                     (int) motionEvent.getX(),
@@ -220,37 +220,36 @@
         FalsingClassifier.Result singleTapResult =
                 mSingleTapClassifier.isTap(mDataProvider.getRecentMotionEvents());
         mPriorResults = Collections.singleton(singleTapResult);
-        if (singleTapResult.isFalse()) {
-            logInfo(String.format(
-                    (Locale) null, "{classifier=%s}", mSingleTapClassifier.getClass().getName()));
-            String reason = singleTapResult.getReason();
-            if (reason != null) {
-                logInfo(reason);
-            }
-            return true;
-        }
 
-        if (robustCheck) {
+        if (!singleTapResult.isFalse() && robustCheck) {
             if (mDataProvider.isJustUnlockedWithFace()) {
                 // Immediately pass if a face is detected.
                 mPriorResults = Collections.singleton(FalsingClassifier.Result.passed(1));
+                logDebug("False Single Tap: false (face detected)");
                 return false;
             } else if (!isFalseDoubleTap()) {
                 // We must check double tapping before other heuristics. This is because
                 // the double tap will fail if there's only been one tap. We don't want that
                 // failure to be recorded in mPriorResults.
+                logDebug("False Single Tap: false (double tapped)");
                 return false;
             } else if (mHistoryTracker.falseBelief() > TAP_CONFIDENCE_THRESHOLD) {
                 mPriorResults = Collections.singleton(
-                        FalsingClassifier.Result.falsed(0, "bad history"));
+                        FalsingClassifier.Result.falsed(
+                                0, getClass().getSimpleName(), "bad history"));
+                logDebug("False Single Tap: true (bad history)");
                 return true;
             } else {
                 mPriorResults = Collections.singleton(FalsingClassifier.Result.passed(0.1));
+                logDebug("False Single Tap: false (default)");
                 return false;
             }
+
+        } else {
+            logDebug("False Single Tap: " + singleTapResult.isFalse() + " (simple)");
+            return singleTapResult.isFalse();
         }
 
-        return false;
     }
 
     @Override
@@ -259,16 +258,12 @@
             return false;
         }
 
-        FalsingClassifier.Result result = mDoubleTapClassifier.classifyGesture();
+        FalsingClassifier.Result result = mDoubleTapClassifier.classifyGesture(
+                Classifier.GENERIC,
+                mHistoryTracker.falseBelief(),
+                mHistoryTracker.falseConfidence());
         mPriorResults = Collections.singleton(result);
-        if (result.isFalse()) {
-            logInfo(String.format(
-                    (Locale) null, "{classifier=%s}", mDoubleTapClassifier.getClass().getName()));
-            String reason = result.getReason();
-            if (reason != null) {
-                logInfo(reason);
-            }
-        }
+        logDebug("False Double Tap: " + result.isFalse());
         return result.isFalse();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java
index ffcdb93..71edbc0 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java
@@ -62,15 +62,16 @@
                 VERTICAL_ANGLE_RANGE);
     }
 
-    Result calculateFalsingResult(double historyBelief, double historyConfidence) {
+    Result calculateFalsingResult(
+            @Classifier.InteractionType int interactionType,
+            double historyBelief, double historyConfidence) {
         float angle = getAngle();
 
         if (angle == Float.MAX_VALUE) {  // Unknown angle
             return Result.passed(0);
         }
 
-        if (getInteractionType() == LEFT_AFFORDANCE
-                || getInteractionType() == RIGHT_AFFORDANCE) {
+        if (interactionType == LEFT_AFFORDANCE || interactionType == RIGHT_AFFORDANCE) {
             return Result.passed(0);
         }
 
@@ -86,7 +87,7 @@
                 || angleBetween(angle, minAngle - NINETY_DEG, maxAngle - NINETY_DEG)
                 || angleBetween(angle, minAngle + ONE_HUNDRED_EIGHTY_DEG,
                 maxAngle + ONE_HUNDRED_EIGHTY_DEG);
-        return falsed ? Result.falsed(0.5f, getReason()) : Result.passed(0.5);
+        return falsed ? falsed(0.5f, getReason()) : Result.passed(0.5);
     }
 
     private String getReason() {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java
index 0f121c1..5a9c386 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java
@@ -136,8 +136,6 @@
         float dX = getLastMotionEvent().getX() - getFirstMotionEvent().getX();
         float dY = getLastMotionEvent().getY() - getFirstMotionEvent().getY();
 
-        logInfo("dX: " + dX + " dY: " + dY + " xV: " + vX + " yV: " + vY);
-
         return new DistanceVectors(dX, dY, vX, vY);
     }
 
@@ -147,9 +145,10 @@
     }
 
     @Override
-    Result calculateFalsingResult(double historyBelief, double historyConfidence) {
-        return !getPassedFlingThreshold()
-                ? Result.falsed(0.5, getReason()) : Result.passed(0.5);
+    Result calculateFalsingResult(
+            @Classifier.InteractionType int interactionType,
+            double historyBelief, double historyConfidence) {
+        return !getPassedFlingThreshold() ? falsed(0.5, getReason()) : Result.passed(0.5);
     }
 
     String getReason() {
@@ -172,7 +171,7 @@
     Result isLongSwipe() {
         boolean longSwipe = getPassedDistanceThreshold();
         logDebug("Is longSwipe? " + longSwipe);
-        return longSwipe ? Result.passed(0.5) : Result.falsed(0.5, getReason());
+        return longSwipe ? Result.passed(0.5) : falsed(0.5, getReason());
     }
 
     private boolean getPassedDistanceThreshold() {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java
index baa54a6..e7c9d18 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java
@@ -46,18 +46,20 @@
     }
 
     @Override
-    Result calculateFalsingResult(double historyBelief, double historyConfidence) {
+    Result calculateFalsingResult(
+            @Classifier.InteractionType int interactionType,
+            double historyBelief, double historyConfidence) {
         List<MotionEvent> secondTapEvents = getRecentMotionEvents();
         List<MotionEvent> firstTapEvents = getPriorMotionEvents();
 
         StringBuilder reason = new StringBuilder();
 
         if (firstTapEvents == null) {
-            return Result.falsed(0, "Only one gesture recorded");
+            return falsed(0, "Only one gesture recorded");
         }
 
         return !isDoubleTap(firstTapEvents, secondTapEvents, reason)
-                ? Result.falsed(0.5, reason.toString()) : Result.passed(0.5);
+                ? falsed(0.5, reason.toString()) : Result.passed(0.5);
     }
 
     /** Returns true if the two supplied lists of {@link MotionEvent}s look like a double-tap. */
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java
index 1af5f7c..81b9f66 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java
@@ -35,6 +35,14 @@
         mDataProvider.addMotionEventListener(mMotionEventListener);
     }
 
+    protected String getFalsingContext() {
+        return getClass().getSimpleName();
+    }
+
+    protected Result falsed(double confidence, String reason) {
+        return Result.falsed(confidence, getFalsingContext(), reason);
+    }
+
     List<MotionEvent> getRecentMotionEvents() {
         return mDataProvider.getRecentMotionEvents();
     }
@@ -87,10 +95,6 @@
         return mDataProvider.getYdpi();
     }
 
-    final @Classifier.InteractionType int getInteractionType() {
-        return mDataProvider.getInteractionType();
-    }
-
     void cleanup() {
         mDataProvider.removeMotionEventListener(mMotionEventListener);
     }
@@ -101,42 +105,32 @@
      * Useful for classifiers that need to see every MotionEvent, but most can probably
      * use {@link #getRecentMotionEvents()} instead, which will return a list of MotionEvents.
      */
-    void onTouchEvent(MotionEvent motionEvent) {};
+    void onTouchEvent(MotionEvent motionEvent) {}
 
     /**
      * Called when a ProximityEvent occurs (change in near/far).
      */
-    void onProximityEvent(ProximitySensor.ThresholdSensorEvent proximityEvent) {};
+    void onProximityEvent(ProximitySensor.ThresholdSensorEvent proximityEvent) {}
 
     /**
      * The phone screen has turned on and we need to begin falsing detection.
      */
-    void onSessionStarted() {};
+    void onSessionStarted() {}
 
     /**
      * The phone screen has turned off and falsing data can be discarded.
      */
-    void onSessionEnded() {};
+    void onSessionEnded() {}
 
     /**
-     * Returns whether a gesture looks like a false touch.
+     * Returns whether a gesture looks like a false touch, taking history into consideration.
      *
-     * See also {@link #classifyGesture(double, double)}.
+     * See {@link HistoryTracker#falseBelief()} and {@link HistoryTracker#falseConfidence()}.
      */
-    Result classifyGesture() {
-        return calculateFalsingResult(0.5, 0);
-    }
-
-    /**
-     * Returns whether a gesture looks like a false touch, with the option to consider history.
-     *
-     * Unlike the parameter-less version of this method, this method allows the classifier to take
-     * history into account, penalizing or boosting confidence in a gesture based on recent results.
-     *
-     * See also {@link #classifyGesture()}.
-     */
-    Result classifyGesture(double historyBelief, double historyConfidence) {
-        return calculateFalsingResult(historyBelief, historyConfidence);
+    Result classifyGesture(
+            @Classifier.InteractionType int interactionType,
+            double historyBelief, double historyConfidence) {
+        return calculateFalsingResult(interactionType, historyBelief, historyConfidence);
     }
 
     /**
@@ -144,7 +138,9 @@
      *
      * When passed a historyConfidence of 0, the history belief should be wholly ignored.
      */
-    abstract Result calculateFalsingResult(double historyBelief, double historyConfidence);
+    abstract Result calculateFalsingResult(
+            @Classifier.InteractionType int interactionType,
+            double historyBelief, double historyConfidence);
 
     /** */
     public static void logDebug(String msg) {
@@ -167,14 +163,16 @@
     public static class Result {
         private final boolean mFalsed;
         private final double mConfidence;
+        private final String mContext;
         private final String mReason;
 
         /**
-         * See {@link #falsed(double, String)} abd {@link #passed(double)}.
+         * See {@link #falsed(double, String, String)} abd {@link #passed(double)}.
          */
-        private Result(boolean falsed, double confidence, String reason) {
+        private Result(boolean falsed, double confidence, String context, String reason) {
             mFalsed = falsed;
             mConfidence = confidence;
+            mContext = context;
             mReason = reason;
         }
 
@@ -187,21 +185,21 @@
         }
 
         public String getReason() {
-            return mReason;
+            return String.format("{context=%s reason=%s}", mContext, mReason);
         }
 
         /**
          * Construct a "falsed" result indicating that a gesture should be treated as accidental.
          */
-        public static Result falsed(double confidence, String reason) {
-            return new Result(true, confidence, reason);
+        public static Result falsed(double confidence, String context, String reason) {
+            return new Result(true, confidence, context, reason);
         }
 
         /**
          * Construct a "passed" result indicating that a gesture should be allowed.
          */
         public static Result passed(double confidence) {
-            return new Result(false, confidence, null);
+            return new Result(false, confidence, null, null);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
index b359860..cf61697 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
@@ -127,7 +127,6 @@
 
     @Override
     public void onNotificationStartDraggingDown() {
-        updateInteractionType(Classifier.NOTIFICATION_DRAG_DOWN);
     }
 
     @Override
@@ -140,7 +139,6 @@
 
     @Override
     public void onQsDown() {
-        updateInteractionType(Classifier.QUICK_SETTINGS);
     }
 
     @Override
@@ -159,7 +157,6 @@
 
     @Override
     public void onTrackingStarted(boolean secure) {
-        updateInteractionType(secure ? Classifier.BOUNCER_UNLOCK : Classifier.UNLOCK);
     }
 
     @Override
@@ -176,8 +173,6 @@
 
     @Override
     public void onAffordanceSwipingStarted(boolean rightCorner) {
-        updateInteractionType(
-                rightCorner ? Classifier.RIGHT_AFFORDANCE : Classifier.LEFT_AFFORDANCE);
     }
 
     @Override
@@ -186,7 +181,6 @@
 
     @Override
     public void onStartExpandingFromPulse() {
-        updateInteractionType(Classifier.PULSE_EXPAND);
     }
 
     @Override
@@ -237,7 +231,6 @@
 
     @Override
     public void onNotificationStartDismissing() {
-        updateInteractionType(Classifier.NOTIFICATION_DISMISS);
     }
 
     @Override
@@ -302,11 +295,6 @@
         mHistoryTracker.addResults(Collections.singleton(result), mSystemClock.uptimeMillis());
     }
 
-    private void updateInteractionType(@Classifier.InteractionType int type) {
-        logDebug("InteractionType: " + type);
-        mFalsingDataProvider.setInteractionType(type);
-    }
-
     private boolean shouldSessionBeActive() {
         return mScreenOn && (mState == StatusBarState.KEYGUARD) && !mShowingAod;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
index 336f13f..f665a74 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
@@ -47,8 +47,6 @@
     private final List<MotionEventListener> mMotionEventListeners = new ArrayList<>();
     private final List<GestureCompleteListener> mGestureCompleteListeners = new ArrayList<>();
 
-    private @Classifier.InteractionType int mInteractionType;
-
     private TimeLimitedMotionEventBuffer mRecentMotionEvents =
             new TimeLimitedMotionEventBuffer(MOTION_EVENT_AGE_MS);
     private List<MotionEvent> mPriorMotionEvents;
@@ -138,21 +136,6 @@
     }
 
     /**
-     * interactionType is defined by {@link com.android.systemui.classifier.Classifier}.
-     */
-    public final void setInteractionType(@Classifier.InteractionType int interactionType) {
-        if (mInteractionType != interactionType) {
-            mInteractionType = interactionType;
-            mDirty = true;
-        }
-    }
-
-    /** Return the interaction type that is being compared against for falsing. */
-    public  final int getInteractionType() {
-        return mInteractionType;
-    }
-
-    /**
      * Get the first recorded {@link MotionEvent} of the most recent gesture.
      *
      * Note that MotionEvents are not kept forever. As a gesture gets longer in duration, older
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java
index 77d2d42..17942a6 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java
@@ -56,14 +56,15 @@
     }
 
     @Override
-    Result calculateFalsingResult(double historyBelief, double historyConfidence) {
-        int interactionType = getInteractionType();
+    Result calculateFalsingResult(
+            @Classifier.InteractionType int interactionType,
+            double historyBelief, double historyConfidence) {
         int allowedPointerCount =
                 (interactionType == QUICK_SETTINGS || interactionType == NOTIFICATION_DRAG_DOWN)
                 ? MAX_ALLOWED_POINTERS_SWIPE_DOWN : MAX_ALLOWED_POINTERS;
 
         return mMaxPointerCount > allowedPointerCount
-                ? Result.falsed(1, getReason(allowedPointerCount)) : Result.passed(0);
+                ? falsed(1, getReason(allowedPointerCount)) : Result.passed(0);
     }
 
     private String getReason(int allowedPointerCount) {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
index 6e97857..ac330f0 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
@@ -112,28 +112,31 @@
     }
 
     @Override
-    Result calculateFalsingResult(double historyBelief, double historyConfidence) {
-        if (getInteractionType() == QUICK_SETTINGS) {
+    Result calculateFalsingResult(
+            @Classifier.InteractionType int interactionType,
+            double historyBelief, double historyConfidence) {
+        if (interactionType == QUICK_SETTINGS) {
             return Result.passed(0);
         }
 
-        logInfo("Percent of gesture in proximity: " + mPercentNear);
-
         if (mPercentNear > mPercentCoveredThreshold) {
             Result longSwipeResult = mDistanceClassifier.isLongSwipe();
             return longSwipeResult.isFalse()
-                    ? Result.falsed(0.5, getReason(longSwipeResult)) : Result.passed(0.5);
+                    ? falsed(
+                            0.5, getReason(longSwipeResult, mPercentNear, mPercentCoveredThreshold))
+                    : Result.passed(0.5);
         }
 
         return Result.passed(0.5);
     }
 
-    private String getReason(Result longSwipeResult) {
+    private static String getReason(Result longSwipeResult, float percentNear,
+            float percentCoveredThreshold) {
         return String.format(
                 (Locale) null,
                 "{percentInProximity=%f, threshold=%f, distanceClassifier=%s}",
-                mPercentNear,
-                mPercentCoveredThreshold,
+                percentNear,
+                percentCoveredThreshold,
                 longSwipeResult.getReason());
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java
index 4dd20cc..68a9e5f 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java
@@ -39,14 +39,16 @@
     }
 
     @Override
-    Result calculateFalsingResult(double historyBelief, double historyConfidence) {
+    Result calculateFalsingResult(
+            @Classifier.InteractionType int interactionType,
+            double historyBelief, double historyConfidence) {
         return isTap(getRecentMotionEvents());
     }
 
     /** Given a list of {@link android.view.MotionEvent}'s, returns true if the look like a tap. */
     public Result isTap(List<MotionEvent> motionEvents) {
         if (motionEvents.isEmpty()) {
-            return Result.falsed(0, "no motion events");
+            return falsed(0, "no motion events");
         }
         float downX = motionEvents.get(0).getX();
         float downY = motionEvents.get(0).getY();
@@ -58,13 +60,13 @@
                         + Math.abs(event.getX() - downX)
                         + "vs "
                         + mTouchSlop;
-                return Result.falsed(0.5, reason);
+                return falsed(0.5, reason);
             } else if (Math.abs(event.getY() - downY) >= mTouchSlop) {
                 reason = "dY too big for a tap: "
                         + Math.abs(event.getY() - downY)
                         + " vs "
                         + mTouchSlop;
-                return Result.falsed(0.5, reason);
+                return falsed(0.5, reason);
             }
         }
         return Result.passed(0);
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java
index 4e032ea..427c2ef 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java
@@ -38,13 +38,15 @@
     }
 
     @Override
-    Result calculateFalsingResult(double historyBelief, double historyConfidence) {
+    Result calculateFalsingResult(
+            @Classifier.InteractionType int interactionType,
+            double historyBelief, double historyConfidence) {
         boolean vertical = isVertical();
         boolean up = isUp();
         boolean right = isRight();
 
         boolean wrongDirection = true;
-        switch (getInteractionType()) {
+        switch (interactionType) {
             case QUICK_SETTINGS:
             case PULSE_EXPAND:
             case NOTIFICATION_DRAG_DOWN:
@@ -68,10 +70,11 @@
                 break;
         }
 
-        return wrongDirection ? Result.falsed(1, getReason()) : Result.passed(0.5);
+        return wrongDirection ? falsed(1, getReason(interactionType)) : Result.passed(0.5);
     }
 
-    private String getReason() {
-        return String.format("{vertical=%s, up=%s, right=%s}", isVertical(), isUp(), isRight());
+    private String getReason(int interactionType) {
+        return String.format("{interaction=%s, vertical=%s, up=%s, right=%s}",
+                interactionType, isVertical(), isUp(), isRight());
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java
index 2058257..1d413af 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java
@@ -84,7 +84,9 @@
     }
 
     @Override
-    Result calculateFalsingResult(double historyBelief, double historyConfidence) {
+    Result calculateFalsingResult(
+            @Classifier.InteractionType int interactionType,
+            double historyBelief, double historyConfidence) {
         List<MotionEvent> motionEvents = getRecentMotionEvents();
         // Rotate horizontal gestures to be horizontal between their first and last point.
         // Rotate vertical gestures to be vertical between their first and last point.
@@ -156,7 +158,7 @@
         logDebug("Straightness Deviance: (" + devianceX + "," + devianceY + ") vs "
                 + "(" + maxXDeviance + "," + maxYDeviance + ")");
         return devianceX > maxXDeviance || devianceY > maxYDeviance
-            ? Result.falsed(0.5, getReason()) : Result.passed(0.5);
+            ? falsed(0.5, getReason()) : Result.passed(0.5);
     }
 
     private String getReason() {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java
index 25d02a6..2a7023a 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java
@@ -19,6 +19,7 @@
 import android.content.BroadcastReceiver;
 
 import com.android.systemui.media.dialog.MediaOutputDialogReceiver;
+import com.android.systemui.people.widget.PeopleSpaceWidgetPinnedReceiver;
 import com.android.systemui.screenshot.ActionProxyReceiver;
 import com.android.systemui.screenshot.DeleteScreenshotReceiver;
 import com.android.systemui.screenshot.SmartActionsReceiver;
@@ -69,4 +70,13 @@
     public abstract BroadcastReceiver bindMediaOutputDialogReceiver(
             MediaOutputDialogReceiver broadcastReceiver);
 
+    /**
+     *
+     */
+    @Binds
+    @IntoMap
+    @ClassKey(PeopleSpaceWidgetPinnedReceiver.class)
+    public abstract BroadcastReceiver bindPeopleSpaceWidgetPinnedReceiver(
+            PeopleSpaceWidgetPinnedReceiver broadcastReceiver);
+
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 123ccee..1a72929 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -31,6 +31,7 @@
 import android.os.Looper;
 import android.os.ServiceManager;
 import android.os.UserHandle;
+import android.service.quickaccesswallet.QuickAccessWalletClient;
 import android.view.Choreographer;
 import android.view.IWindowManager;
 import android.view.LayoutInflater;
@@ -45,8 +46,11 @@
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
+import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
+import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
 import com.android.systemui.accessibility.ModeSwitchesController;
 import com.android.systemui.accessibility.SystemActions;
+import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger;
@@ -212,6 +216,7 @@
             MetricsLogger metricsLogger,
             OverviewProxyService overviewProxyService,
             NavigationModeController navigationModeController,
+            AccessibilityButtonModeObserver accessibilityButtonModeObserver,
             StatusBarStateController statusBarStateController,
             SysUiState sysUiFlagsContainer,
             BroadcastDispatcher broadcastDispatcher,
@@ -236,6 +241,7 @@
                 metricsLogger,
                 overviewProxyService,
                 navigationModeController,
+                accessibilityButtonModeObserver,
                 statusBarStateController,
                 sysUiFlagsContainer,
                 broadcastDispatcher,
@@ -256,6 +262,16 @@
     /** */
     @Provides
     @SysUISingleton
+    public AccessibilityFloatingMenuController provideAccessibilityFloatingMenuController(
+            Context context, AccessibilityButtonTargetsObserver accessibilityButtonTargetsObserver,
+            AccessibilityButtonModeObserver accessibilityButtonModeObserver) {
+        return new AccessibilityFloatingMenuController(context, accessibilityButtonTargetsObserver,
+                accessibilityButtonModeObserver);
+    }
+
+    /** */
+    @Provides
+    @SysUISingleton
     public ConfigurationController provideConfigurationController(Context context) {
         return new ConfigurationControllerImpl(context);
     }
@@ -360,4 +376,11 @@
     public ModeSwitchesController providesModeSwitchesController(Context context) {
         return new ModeSwitchesController(context);
     }
+
+    /** */
+    @Provides
+    @SysUISingleton
+    public QuickAccessWalletClient provideQuickAccessWalletClient(Context context) {
+        return QuickAccessWalletClient.create(context);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index 8f79de5..ed3d5ec 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -34,7 +34,7 @@
 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 com.android.wm.shell.transition.ShellTransitions;
 
 import java.util.Optional;
 
@@ -87,7 +87,7 @@
         Builder setShellCommandHandler(Optional<ShellCommandHandler> shellDump);
 
         @BindsInstance
-        Builder setTransitions(RemoteTransitions t);
+        Builder setTransitions(ShellTransitions t);
 
         @BindsInstance
         Builder setStartingSurface(Optional<StartingSurface> s);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index 1b77d1c..bbd95b4 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -33,7 +33,7 @@
 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 com.android.wm.shell.transition.ShellTransitions;
 
 import java.util.Optional;
 
@@ -98,7 +98,7 @@
     Optional<TaskViewFactory> getTaskViewFactory();
 
     @WMSingleton
-    RemoteTransitions getTransitions();
+    ShellTransitions getTransitions();
 
     @WMSingleton
     Optional<StartingSurface> getStartingSurface();
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java
index 1a53c28..58c41d5 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java
@@ -29,6 +29,7 @@
 import static android.opengl.GLES20.glEnableVertexAttribArray;
 import static android.opengl.GLES20.glGenTextures;
 import static android.opengl.GLES20.glTexParameteri;
+import static android.opengl.GLES20.glUniform1f;
 import static android.opengl.GLES20.glUniform1i;
 import static android.opengl.GLES20.glVertexAttribPointer;
 
@@ -52,6 +53,7 @@
     private static final String A_POSITION = "aPosition";
     private static final String A_TEXTURE_COORDINATES = "aTextureCoordinates";
     private static final String U_TEXTURE = "uTexture";
+    private static final String U_EXPOSURE = "uExposure";
     private static final int POSITION_COMPONENT_COUNT = 2;
     private static final int TEXTURE_COMPONENT_COUNT = 2;
     private static final int BYTES_PER_FLOAT = 4;
@@ -83,6 +85,7 @@
     private int mAttrPosition;
     private int mAttrTextureCoordinates;
     private int mUniTexture;
+    private int mUniExposure;
     private int mTextureId;
 
     ImageGLWallpaper(ImageGLProgram program) {
@@ -125,6 +128,7 @@
 
     private void setupUniforms() {
         mUniTexture = mProgram.getUniformHandle(U_TEXTURE);
+        mUniExposure = mProgram.getUniformHandle(U_EXPOSURE);
     }
 
     void draw() {
@@ -171,6 +175,10 @@
         glUniform1i(mUniTexture, 0);
     }
 
+    void setExposureValue(float exposureValue) {
+        glUniform1f(mUniExposure, exposureValue);
+    }
+
     /**
      * Called to dump current state.
      * @param prefix prefix.
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java
index 01a353c..cdf88f3 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java
+++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java
@@ -46,6 +46,7 @@
     private final ImageGLWallpaper mWallpaper;
     private final Rect mSurfaceSize = new Rect();
     private final WallpaperTexture mTexture;
+    private float mExposureValue;
 
     public ImageWallpaperRenderer(Context context) {
         final WallpaperManager wpm = context.getSystemService(WallpaperManager.class);
@@ -66,6 +67,13 @@
         mTexture.use(c);
     }
 
+    /**
+     * @hide
+     */
+    public void setExposureValue(float exposureValue) {
+        mExposureValue = exposureValue;
+    }
+
     @Override
     public boolean isWcgContent() {
         return mTexture.isWcgContent();
@@ -94,6 +102,7 @@
     public void onDrawFrame() {
         glClear(GL_COLOR_BUFFER_BIT);
         glViewport(0, 0, mSurfaceSize.width(), mSurfaceSize.height());
+        mWallpaper.setExposureValue(mExposureValue);
         mWallpaper.useTexture();
         mWallpaper.draw();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 9d29822..9d43e0c 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -23,6 +23,7 @@
 import static android.app.StatusBarManager.WindowType;
 import static android.app.StatusBarManager.WindowVisibleState;
 import static android.app.StatusBarManager.windowStateToString;
+import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
 import static android.view.InsetsState.containsType;
@@ -113,6 +114,7 @@
 import com.android.internal.view.AppearanceRegion;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
+import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
 import com.android.systemui.accessibility.SystemActions;
 import com.android.systemui.assist.AssistHandleViewController;
 import com.android.systemui.assist.AssistManager;
@@ -158,7 +160,8 @@
  * Contains logic for a navigation bar view.
  */
 public class NavigationBar implements View.OnAttachStateChangeListener,
-        Callbacks, NavigationModeController.ModeChangedListener, DisplayManager.DisplayListener {
+        Callbacks, NavigationModeController.ModeChangedListener,
+        AccessibilityButtonModeObserver.ModeChangedListener, DisplayManager.DisplayListener {
 
     public static final String TAG = "NavigationBar";
     private static final boolean DEBUG = false;
@@ -186,6 +189,7 @@
     private final NotificationRemoteInputManager mNotificationRemoteInputManager;
     private final OverviewProxyService mOverviewProxyService;
     private final NavigationModeController mNavigationModeController;
+    private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
     private final BroadcastDispatcher mBroadcastDispatcher;
     private final CommandQueue mCommandQueue;
     private final Optional<Pip> mPipOptional;
@@ -226,6 +230,7 @@
 
     private boolean mTransientShown;
     private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
+    private int mA11yBtnMode;
     private LightBarController mLightBarController;
     private AutoHideController mAutoHideController;
 
@@ -271,7 +276,7 @@
 
     /** Only for default display */
     @Nullable
-    private AssistHandleViewController mAssistHandlerViewController;
+    AssistHandleViewController mAssistHandlerViewController;
 
 
     private final AutoHideUiElement mAutoHideUiElement = new AutoHideUiElement() {
@@ -443,6 +448,7 @@
             MetricsLogger metricsLogger,
             OverviewProxyService overviewProxyService,
             NavigationModeController navigationModeController,
+            AccessibilityButtonModeObserver accessibilityButtonModeObserver,
             StatusBarStateController statusBarStateController,
             SysUiState sysUiFlagsContainer,
             BroadcastDispatcher broadcastDispatcher,
@@ -470,7 +476,7 @@
         mNotificationRemoteInputManager = notificationRemoteInputManager;
         mOverviewProxyService = overviewProxyService;
         mNavigationModeController = navigationModeController;
-        mNavBarMode = navigationModeController.addListener(this);
+        mAccessibilityButtonModeObserver = accessibilityButtonModeObserver;
         mBroadcastDispatcher = broadcastDispatcher;
         mCommandQueue = commandQueue;
         mPipOptional = pipOptional;
@@ -480,6 +486,10 @@
         mHandler = mainHandler;
         mNavbarOverlayController = navbarOverlayController;
         mUiEventLogger = uiEventLogger;
+
+        mNavBarMode = mNavigationModeController.addListener(this);
+        mAccessibilityButtonModeObserver.addListener(this);
+        mA11yBtnMode = mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode();
     }
 
     public View getView() {
@@ -552,6 +562,8 @@
         mIsCurrentUserSetup = mDeviceProvisionedController.isCurrentUserSetup();
         mDeviceProvisionedController.addCallback(mUserSetupListener);
 
+        setAccessibilityFloatingMenuModeIfNeeded();
+
         return barView;
     }
 
@@ -560,6 +572,7 @@
         mContext.getSystemService(WindowManager.class).removeViewImmediate(
                 mNavigationBarView.getRootView());
         mNavigationModeController.removeListener(this);
+        mAccessibilityButtonModeObserver.removeListener(this);
 
         mAccessibilityManagerWrapper.removeCallback(mAccessibilityListener);
         mContentResolver.unregisterContentObserver(mAssistContentObserver);
@@ -1381,7 +1394,7 @@
         return true;
     }
 
-    private void updateAccessibilityServicesState(AccessibilityManager accessibilityManager) {
+    void updateAccessibilityServicesState(AccessibilityManager accessibilityManager) {
         if (mNavigationBarView == null) {
             return;
         }
@@ -1395,6 +1408,13 @@
         updateSystemUiStateFlags(a11yFlags);
     }
 
+    private void setAccessibilityFloatingMenuModeIfNeeded() {
+        if (QuickStepContract.isGesturalMode(mNavBarMode)) {
+            Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
+                    ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU);
+        }
+    }
+
     public void updateSystemUiStateFlags(int a11yFlags) {
         if (a11yFlags < 0) {
             a11yFlags = getA11yButtonState(null);
@@ -1450,6 +1470,12 @@
             outFeedbackEnabled[0] = feedbackEnabled;
         }
 
+        // If accessibility button is floating menu mode, click and long click state should be
+        // disabled.
+        if (mA11yBtnMode == ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU) {
+            return 0;
+        }
+
         return (requestingServices >= 1 ? SYSUI_STATE_A11Y_BUTTON_CLICKABLE : 0)
                 | (requestingServices >= 2 ? SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE : 0);
     }
@@ -1534,12 +1560,19 @@
             }
         }
         updateScreenPinningGestures();
+        setAccessibilityFloatingMenuModeIfNeeded();
 
         if (!canShowSecondaryHandle()) {
             resetSecondaryHandle();
         }
     }
 
+    @Override
+    public void onAccessibilityButtonModeChanged(int mode) {
+        mA11yBtnMode = mode;
+        updateAccessibilityServicesState(mAccessibilityManager);
+    }
+
     public void disableAnimationsDuringHide(long delay) {
         mNavigationBarView.setLayoutTransitionsEnabled(false);
         mNavigationBarView.postDelayed(() -> mNavigationBarView.setLayoutTransitionsEnabled(true),
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index 0bfd065..50efa8d 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -43,6 +43,7 @@
 import com.android.internal.statusbar.RegisterStatusBarResult;
 import com.android.settingslib.applications.InterestingConfigChanges;
 import com.android.systemui.Dumpable;
+import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
 import com.android.systemui.accessibility.SystemActions;
 import com.android.systemui.assist.AssistHandleViewController;
 import com.android.systemui.assist.AssistManager;
@@ -91,6 +92,7 @@
     private final MetricsLogger mMetricsLogger;
     private final OverviewProxyService mOverviewProxyService;
     private final NavigationModeController mNavigationModeController;
+    private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
     private final StatusBarStateController mStatusBarStateController;
     private final SysUiState mSysUiFlagsContainer;
     private final BroadcastDispatcher mBroadcastDispatcher;
@@ -127,6 +129,7 @@
             MetricsLogger metricsLogger,
             OverviewProxyService overviewProxyService,
             NavigationModeController navigationModeController,
+            AccessibilityButtonModeObserver accessibilityButtonModeObserver,
             StatusBarStateController statusBarStateController,
             SysUiState sysUiFlagsContainer,
             BroadcastDispatcher broadcastDispatcher,
@@ -151,6 +154,7 @@
         mMetricsLogger = metricsLogger;
         mOverviewProxyService = overviewProxyService;
         mNavigationModeController = navigationModeController;
+        mAccessibilityButtonModeObserver = accessibilityButtonModeObserver;
         mStatusBarStateController = statusBarStateController;
         mSysUiFlagsContainer = sysUiFlagsContainer;
         mBroadcastDispatcher = broadcastDispatcher;
@@ -289,6 +293,7 @@
                 mMetricsLogger,
                 mOverviewProxyService,
                 mNavigationModeController,
+                mAccessibilityButtonModeObserver,
                 mStatusBarStateController,
                 mSysUiFlagsContainer,
                 mBroadcastDispatcher,
@@ -324,7 +329,7 @@
         });
     }
 
-    private void removeNavigationBar(int displayId) {
+    void removeNavigationBar(int displayId) {
         NavigationBar navBar = mNavigationBars.get(displayId);
         if (navBar != null) {
             navBar.setAutoHideController(/* autoHideController */ null);
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java
index 2707460..7342f91 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java
@@ -40,9 +40,9 @@
 import com.android.systemui.navigationbar.buttons.ButtonDispatcher;
 import com.android.systemui.navigationbar.buttons.KeyButtonView;
 import com.android.systemui.navigationbar.buttons.ReverseLinearLayout;
+import com.android.systemui.navigationbar.buttons.ReverseLinearLayout.ReverseRelativeLayout;
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.navigationbar.buttons.ReverseLinearLayout.ReverseRelativeLayout;
 
 import java.io.PrintWriter;
 import java.util.Objects;
@@ -361,7 +361,7 @@
         return v;
     }
 
-    private View createView(String buttonSpec, ViewGroup parent, LayoutInflater inflater) {
+    View createView(String buttonSpec, ViewGroup parent, LayoutInflater inflater) {
         View v = null;
         String button = extractButton(buttonSpec);
         if (LEFT.equals(button)) {
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleProvider.java b/packages/SystemUI/src/com/android/systemui/people/PeopleProvider.java
index 6295692..59329d1 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleProvider.java
@@ -16,9 +16,7 @@
 
 package com.android.systemui.people;
 
-import android.app.people.ConversationChannel;
 import android.app.people.IPeopleManager;
-import android.app.people.PeopleSpaceTile;
 import android.content.ContentProvider;
 import android.content.ContentValues;
 import android.content.Context;
@@ -33,13 +31,16 @@
 import android.util.Log;
 import android.widget.RemoteViews;
 
+import com.android.systemui.Dependency;
 import com.android.systemui.shared.system.PeopleProviderUtils;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
 
 /** API that returns a People Tile preview. */
 public class PeopleProvider extends ContentProvider {
 
     LauncherApps mLauncherApps;
     IPeopleManager mPeopleManager;
+    NotificationEntryManager mNotificationEntryManager;
 
     private static final String TAG = "PeopleProvider";
     private static final boolean DEBUG = PeopleSpaceUtils.DEBUG;
@@ -57,18 +58,6 @@
             throw new IllegalArgumentException("Invalid method");
         }
 
-        // If services are not set as mocks in tests, fetch them now.
-        mPeopleManager = mPeopleManager != null ? mPeopleManager
-                : IPeopleManager.Stub.asInterface(
-                        ServiceManager.getService(Context.PEOPLE_SERVICE));
-        mLauncherApps = mLauncherApps != null ? mLauncherApps
-                : getContext().getSystemService(LauncherApps.class);
-
-        if (mPeopleManager == null || mLauncherApps == null) {
-            Log.w(TAG, "Null system managers");
-            return null;
-        }
-
         if (extras == null) {
             Log.w(TAG, "Extras can't be null");
             throw new IllegalArgumentException("Extras can't be null");
@@ -94,24 +83,22 @@
             throw new IllegalArgumentException("Null user handle");
         }
 
-        ConversationChannel channel;
-        try {
-            channel = mPeopleManager.getConversation(
-                    packageName, userHandle.getIdentifier(), shortcutId);
-        } catch (Exception e) {
-            Log.w(TAG, "Exception getting tiles: " + e);
+        // If services are not set as mocks in tests, fetch them now.
+        mPeopleManager = mPeopleManager != null ? mPeopleManager
+                : IPeopleManager.Stub.asInterface(
+                        ServiceManager.getService(Context.PEOPLE_SERVICE));
+        mLauncherApps = mLauncherApps != null ? mLauncherApps
+                : getContext().getSystemService(LauncherApps.class);
+        mNotificationEntryManager = mNotificationEntryManager != null ? mNotificationEntryManager
+                : Dependency.get(NotificationEntryManager.class);
+
+        RemoteViews view = PeopleSpaceUtils.getPreview(getContext(), mPeopleManager, mLauncherApps,
+                mNotificationEntryManager, shortcutId, userHandle, packageName);
+        if (view == null) {
+            if (DEBUG) Log.d(TAG, "No preview available for shortcutId: " + shortcutId);
             return null;
         }
-        PeopleSpaceTile tile = PeopleSpaceUtils.getTile(channel, mLauncherApps);
-
-        if (tile == null) {
-            if (DEBUG) Log.i(TAG, "No tile was returned");
-            return null;
-        }
-
-        if (DEBUG) Log.i(TAG, "Returning tile preview for shortcutId: " + shortcutId);
         final Bundle bundle = new Bundle();
-        RemoteViews view = PeopleSpaceUtils.createRemoteViews(getContext(), tile, 0, bundle);
         bundle.putParcelable(PeopleProviderUtils.RESPONSE_KEY_REMOTE_VIEWS, view);
         return bundle;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
index 378e49d..54d6a2e 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
@@ -29,13 +29,11 @@
 import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.os.ServiceManager;
-import android.provider.Settings;
 import android.util.Log;
 import android.view.ViewGroup;
 
 import com.android.systemui.R;
 import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
-import com.android.systemui.people.widget.PeopleTileKey;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 
 import java.util.List;
@@ -59,12 +57,14 @@
     private Context mContext;
     private NotificationEntryManager mNotificationEntryManager;
     private int mAppWidgetId;
-    private boolean mShowSingleConversation;
 
     @Inject
-    public PeopleSpaceActivity(NotificationEntryManager notificationEntryManager) {
+    public PeopleSpaceActivity(NotificationEntryManager notificationEntryManager,
+            PeopleSpaceWidgetManager peopleSpaceWidgetManager) {
         super();
         mNotificationEntryManager = notificationEntryManager;
+        mPeopleSpaceWidgetManager = peopleSpaceWidgetManager;
+
     }
 
     @Override
@@ -78,20 +78,11 @@
         mPackageManager = getPackageManager();
         mPeopleManager = IPeopleManager.Stub.asInterface(
                 ServiceManager.getService(Context.PEOPLE_SERVICE));
-        mPeopleSpaceWidgetManager = new PeopleSpaceWidgetManager(mContext);
         mLauncherApps = mContext.getSystemService(LauncherApps.class);
         setTileViewsWithPriorityConversations();
         mAppWidgetId = getIntent().getIntExtra(EXTRA_APPWIDGET_ID,
                 INVALID_APPWIDGET_ID);
-        mShowSingleConversation = Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 0;
         setResult(RESULT_CANCELED);
-        // Finish the configuration activity immediately if a widget is added for multiple
-        // conversations. If the mAppWidgetId is INVALID, then the activity wasn't launched as a
-        // widget configuration activity.
-        if (!mShowSingleConversation && mAppWidgetId != INVALID_APPWIDGET_ID) {
-            finishActivity();
-        }
     }
 
     /**
@@ -139,9 +130,7 @@
                         + mAppWidgetId);
             }
         }
-        PeopleTileKey key = new PeopleTileKey(
-                tile.getId(), tile.getUserHandle().getIdentifier(), tile.getPackageName());
-        mPeopleSpaceWidgetManager.addNewWidget(mAppWidgetId, key);
+        mPeopleSpaceWidgetManager.addNewWidget(mAppWidgetId, tile);
         finishActivity();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
index e07e9cf..f9c2a2a 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
@@ -19,12 +19,13 @@
 import static android.app.Notification.CATEGORY_MISSED_CALL;
 import static android.app.Notification.EXTRA_MESSAGES;
 import static android.app.people.ConversationStatus.ACTIVITY_ANNIVERSARY;
+import static android.app.people.ConversationStatus.ACTIVITY_AUDIO;
 import static android.app.people.ConversationStatus.ACTIVITY_BIRTHDAY;
 import static android.app.people.ConversationStatus.ACTIVITY_GAME;
 import static android.app.people.ConversationStatus.ACTIVITY_LOCATION;
-import static android.app.people.ConversationStatus.ACTIVITY_MEDIA;
 import static android.app.people.ConversationStatus.ACTIVITY_NEW_STORY;
 import static android.app.people.ConversationStatus.ACTIVITY_UPCOMING_BIRTHDAY;
+import static android.app.people.ConversationStatus.ACTIVITY_VIDEO;
 import static android.app.people.ConversationStatus.AVAILABILITY_AVAILABLE;
 import static android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT;
 import static android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH;
@@ -59,8 +60,9 @@
 import android.net.Uri;
 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;
 import android.service.notification.StatusBarNotification;
 import android.text.TextUtils;
@@ -92,7 +94,6 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Date;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
@@ -169,8 +170,6 @@
             Context context, INotificationManager notificationManager, IPeopleManager peopleManager,
             LauncherApps launcherApps, NotificationEntryManager notificationEntryManager)
             throws Exception {
-        boolean showOnlyPriority = Settings.Global.getInt(context.getContentResolver(),
-                Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 1;
         List<ConversationChannelWrapper> conversations =
                 notificationManager.getConversations(
                         false).getList();
@@ -183,116 +182,28 @@
                 priorityConversations);
 
         // Sort and then add recent and non priority conversations to tiles list.
-        if (!showOnlyPriority) {
-            if (DEBUG) Log.d(TAG, "Add recent conversations");
-            Stream<ShortcutInfo> nonPriorityConversations = conversations.stream()
-                    .filter(c -> c.getNotificationChannel() == null
-                            || !c.getNotificationChannel().isImportantConversation())
-                    .map(c -> c.getShortcutInfo());
+        if (DEBUG) Log.d(TAG, "Add recent conversations");
+        Stream<ShortcutInfo> nonPriorityConversations = conversations.stream()
+                .filter(c -> c.getNotificationChannel() == null
+                        || !c.getNotificationChannel().isImportantConversation())
+                .map(c -> c.getShortcutInfo());
 
-            List<ConversationChannel> recentConversationsList =
-                    peopleManager.getRecentConversations().getList();
-            Stream<ShortcutInfo> recentConversations = recentConversationsList
-                    .stream()
-                    .map(c -> c.getShortcutInfo());
+        List<ConversationChannel> recentConversationsList =
+                peopleManager.getRecentConversations().getList();
+        Stream<ShortcutInfo> recentConversations = recentConversationsList
+                .stream()
+                .map(c -> c.getShortcutInfo());
 
-            Stream<ShortcutInfo> mergedStream = Stream.concat(nonPriorityConversations,
-                    recentConversations);
-            List<PeopleSpaceTile> recentTiles =
-                    getSortedTiles(peopleManager, launcherApps, mergedStream);
-            tiles.addAll(recentTiles);
-        }
+        Stream<ShortcutInfo> mergedStream = Stream.concat(nonPriorityConversations,
+                recentConversations);
+        List<PeopleSpaceTile> recentTiles =
+                getSortedTiles(peopleManager, launcherApps, mergedStream);
+        tiles.addAll(recentTiles);
 
         tiles = augmentTilesFromVisibleNotifications(context, tiles, notificationEntryManager);
         return tiles;
     }
 
-    /**
-     * Updates {@code appWidgetIds} with their associated conversation stored, handling a
-     * notification being posted or removed.
-     */
-    public static void updateSingleConversationWidgets(Context context, int[] appWidgetIds,
-            AppWidgetManager appWidgetManager, IPeopleManager peopleManager) {
-        Map<Integer, PeopleSpaceTile> widgetIdToTile = new HashMap<>();
-        for (int appWidgetId : appWidgetIds) {
-            PeopleSpaceTile tile = getPeopleSpaceTile(
-                    context, appWidgetId, appWidgetManager, peopleManager);
-            if (tile == null) {
-                if (DEBUG) Log.d(TAG, "Matching conversation not found for shortcut ID");
-                //TODO: Delete app widget id when crash is fixed (b/172932636)
-                continue;
-            }
-            Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetId);
-            updateAppWidgetViews(appWidgetManager, context, appWidgetId, tile, options);
-            widgetIdToTile.put(appWidgetId, tile);
-        }
-        getBirthdaysOnBackgroundThread(context, appWidgetManager, widgetIdToTile, appWidgetIds);
-    }
-
-    /**
-     * Returns a {@link PeopleSpaceTile} based on the {@code appWidgetId}. If the PeopleSpaceTile
-     * isn't cached, store it in AppWidgetOptions.
-     */
-    @Nullable
-    public static PeopleSpaceTile getPeopleSpaceTile(Context context, int appWidgetId,
-            AppWidgetManager appWidgetManager, IPeopleManager peopleManager) {
-        // First, check if tile is cached in AppWidgetOptions.
-        PeopleSpaceTile tile = AppWidgetOptionsHelper.getPeopleTile(appWidgetManager, appWidgetId);
-        if (tile != null) {
-            if (DEBUG) Log.d(TAG, "People Tile is cached for widget: " + appWidgetId);
-            return tile;
-        }
-
-        // If not, we get the PeopleTileKey from SharedPreferences, retrieve the Conversation from
-        // persisted storage, and cache it in AppWidgetOptions.
-        SharedPreferences widgetSp = context.getSharedPreferences(
-                String.valueOf(appWidgetId),
-                Context.MODE_PRIVATE);
-        PeopleTileKey sharedPreferencesKey = new PeopleTileKey(
-                widgetSp.getString(SHORTCUT_ID, EMPTY_STRING),
-                widgetSp.getInt(USER_ID, INVALID_USER_ID),
-                widgetSp.getString(PACKAGE_NAME, EMPTY_STRING));
-
-        if (!sharedPreferencesKey.isValid()) {
-            Log.e(TAG, "Cannot find shortcut info for widgetId: " + appWidgetId);
-            return null;
-        }
-
-        if (DEBUG) Log.d(TAG, "PeopleTile key is present in sharedPreferences: " + appWidgetId);
-        // If tile is null, we need to retrieve from persisted storage.
-        return getPeopleTileFromPersistentStorage(context, sharedPreferencesKey, peopleManager);
-    }
-
-    /**
-     * Returns a {@link PeopleSpaceTile} based on {@link ConversationChannel} returned by
-     * {@link IPeopleManager}.
-     */
-    public static PeopleSpaceTile getPeopleTileFromPersistentStorage(Context context,
-            PeopleTileKey peopleTileKey, IPeopleManager peopleManager) {
-        try {
-            if (DEBUG) Log.d(TAG, "Retrieving Tile from storage: " + peopleTileKey.toString());
-            LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
-            if (launcherApps == null) {
-                Log.d(TAG, "LauncherApps is null");
-                return null;
-            }
-
-            ConversationChannel channel = peopleManager.getConversation(
-                    peopleTileKey.getPackageName(),
-                    peopleTileKey.getUserId(),
-                    peopleTileKey.getShortcutId());
-            if (channel == null) {
-                Log.d(TAG, "Could not retrieve conversation from storage");
-                return null;
-            }
-
-            return new PeopleSpaceTile.Builder(channel, launcherApps).build();
-        } catch (Exception e) {
-            Log.e(TAG, "Failed to retrieve conversation for tile: " + e);
-            return null;
-        }
-    }
-
     /** Returns stored widgets for the conversation specified. */
     public static Set<String> getStoredWidgetIds(SharedPreferences sp, PeopleTileKey key) {
         if (!key.isValid()) {
@@ -347,6 +258,14 @@
         widgetEditor.apply();
     }
 
+    /** Augments a single {@link PeopleSpaceTile} with notification content, if one is present. */
+    public static PeopleSpaceTile augmentSingleTileFromVisibleNotifications(Context context,
+            PeopleSpaceTile tile, NotificationEntryManager notificationEntryManager) {
+        List<PeopleSpaceTile> augmentedTile = augmentTilesFromVisibleNotifications(
+                context, Arrays.asList(tile), notificationEntryManager);
+        return augmentedTile.get(0);
+    }
+
     static List<PeopleSpaceTile> augmentTilesFromVisibleNotifications(Context context,
             List<PeopleSpaceTile> tiles, NotificationEntryManager notificationEntryManager) {
         if (notificationEntryManager == null) {
@@ -578,8 +497,10 @@
                 return context.getString(R.string.location_status);
             case ACTIVITY_NEW_STORY:
                 return context.getString(R.string.new_story_status);
-            case ACTIVITY_MEDIA:
+            case ACTIVITY_VIDEO:
                 return context.getString(R.string.video_status);
+            case ACTIVITY_AUDIO:
+                return context.getString(R.string.audio_status);
             case ACTIVITY_GAME:
                 return context.getString(R.string.game_status);
             default:
@@ -914,7 +835,7 @@
     }
 
     /** Calls to retrieve birthdays on a background thread. */
-    private static void getBirthdaysOnBackgroundThread(Context context,
+    public static void getBirthdaysOnBackgroundThread(Context context,
             AppWidgetManager appWidgetManager,
             Map<Integer, PeopleSpaceTile> peopleSpaceTiles, int[] appWidgetIds) {
         ThreadUtils.postOnBackgroundThread(
@@ -992,7 +913,8 @@
         removeBirthdayStatusIfPresent(appWidgetManager, context, storedTile, appWidgetId);
     }
 
-    private static void updateAppWidgetViews(AppWidgetManager appWidgetManager,
+    /** Updates the current widget view with provided {@link PeopleSpaceTile}. */
+    public static void updateAppWidgetViews(AppWidgetManager appWidgetManager,
             Context context, int appWidgetId, PeopleSpaceTile tile, Bundle options) {
         if (DEBUG) Log.d(TAG, "Widget: " + appWidgetId + ", " + tile.getUserName());
         RemoteViews views = createRemoteViews(context, tile, appWidgetId, options);
@@ -1049,6 +971,43 @@
         return lookupKeysWithBirthdaysToday;
     }
 
+    /**
+     * Returns a {@link RemoteViews} preview of a Conversation's People Tile. Returns null if one
+     * is not available.
+     */
+    public static RemoteViews getPreview(Context context, IPeopleManager peopleManager,
+            LauncherApps launcherApps, NotificationEntryManager notificationEntryManager,
+            String shortcutId, UserHandle userHandle, String packageName) {
+        peopleManager = (peopleManager != null) ? peopleManager : IPeopleManager.Stub.asInterface(
+                ServiceManager.getService(Context.PEOPLE_SERVICE));
+        launcherApps = (launcherApps != null) ? launcherApps
+                : context.getSystemService(LauncherApps.class);
+        if (peopleManager == null || launcherApps == null) {
+            return null;
+        }
+
+        ConversationChannel channel;
+        try {
+            channel = peopleManager.getConversation(
+                    packageName, userHandle.getIdentifier(), shortcutId);
+        } catch (Exception e) {
+            Log.w(TAG, "Exception getting tiles: " + e);
+            return null;
+        }
+        PeopleSpaceTile tile = PeopleSpaceUtils.getTile(channel, launcherApps);
+
+        if (tile == null) {
+            if (DEBUG) Log.i(TAG, "No tile was returned");
+            return null;
+        }
+        PeopleSpaceTile augmentedTile = augmentSingleTileFromVisibleNotifications(
+                context, tile, notificationEntryManager);
+
+        if (DEBUG) Log.i(TAG, "Returning tile preview for shortcutId: " + shortcutId);
+        Bundle bundle = new Bundle();
+        return PeopleSpaceUtils.createRemoteViews(context, augmentedTile, 0, bundle);
+    }
+
     /** Returns the userId associated with a {@link PeopleSpaceTile} */
     public static int getUserId(PeopleSpaceTile tile) {
         return tile.getUserHandle().getIdentifier();
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 48f6184..c01a52d 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java
@@ -27,6 +27,7 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.UiEventLoggerImpl;
 import com.android.internal.statusbar.IStatusBarService;
@@ -34,6 +35,9 @@
 import com.android.systemui.people.PeopleSpaceUtils;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.wmshell.BubblesManager;
+
+import java.util.Optional;
 
 import javax.inject.Inject;
 
@@ -43,16 +47,23 @@
     private static final boolean DEBUG = PeopleSpaceUtils.DEBUG;
     private UiEventLogger mUiEventLogger = new UiEventLoggerImpl();
     private NotificationEntryManager mNotificationEntryManager;
+    private final Optional<BubblesManager> mBubblesManagerOptional;
+    private boolean mIsForTesting;
+    private IStatusBarService mIStatusBarService;
 
     @Inject
-    public LaunchConversationActivity(NotificationEntryManager notificationEntryManager) {
+    public LaunchConversationActivity(NotificationEntryManager notificationEntryManager,
+            Optional<BubblesManager> bubblesManagerOptional) {
         super();
         mNotificationEntryManager = notificationEntryManager;
+        mBubblesManagerOptional = bubblesManagerOptional;
     }
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
+        if (!mIsForTesting) {
+            super.onCreate(savedInstanceState);
+        }
         if (DEBUG) Log.d(TAG, "onCreate called");
 
         Intent intent = getIntent();
@@ -63,21 +74,30 @@
         String notificationKey =
                 intent.getStringExtra(PeopleSpaceWidgetProvider.EXTRA_NOTIFICATION_KEY);
 
-        if (tileId != null && !tileId.isEmpty()) {
+        if (!TextUtils.isEmpty(tileId)) {
             if (DEBUG) {
                 Log.d(TAG, "Launching conversation with shortcutInfo id " + tileId);
             }
             mUiEventLogger.log(PeopleSpaceUtils.PeopleSpaceWidgetEvent.PEOPLE_SPACE_WIDGET_CLICKED);
             try {
+                NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(
+                        notificationKey);
+                if (entry != null && entry.canBubble() && mBubblesManagerOptional.isPresent()) {
+                    if (DEBUG) Log.d(TAG, "Open bubble for conversation");
+                    mBubblesManagerOptional.get().expandStackAndSelectBubble(entry);
+                    // Just opt-out and don't cancel the notification for bubbles.
+                    return;
+                }
+
+                if (mIStatusBarService == null) {
+                    mIStatusBarService = IStatusBarService.Stub.asInterface(
+                            ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+                }
+                clearNotificationIfPresent(notificationKey, packageName, userHandle);
                 LauncherApps launcherApps =
                         getApplicationContext().getSystemService(LauncherApps.class);
                 launcherApps.startShortcut(
                         packageName, tileId, null, null, userHandle);
-
-                IStatusBarService statusBarService = IStatusBarService.Stub.asInterface(
-                        ServiceManager.getService(Context.STATUS_BAR_SERVICE));
-                clearNotificationIfPresent(
-                        statusBarService, notificationKey, packageName, userHandle);
             } catch (Exception e) {
                 Log.e(TAG, "Exception:" + e);
             }
@@ -87,15 +107,14 @@
         finish();
     }
 
-    void clearNotificationIfPresent(IStatusBarService statusBarService,
-            String notifKey, String packageName, UserHandle userHandle) {
+    void clearNotificationIfPresent(String notifKey, String packageName, UserHandle userHandle) {
         if (TextUtils.isEmpty(notifKey)) {
             if (DEBUG) Log.d(TAG, "Skipping clear notification: notification key is empty");
             return;
         }
 
         try {
-            if (statusBarService == null || mNotificationEntryManager == null) {
+            if (mIStatusBarService == null || mNotificationEntryManager == null) {
                 if (DEBUG) {
                     Log.d(TAG, "Skipping clear notification: null services, key: " + notifKey);
                 }
@@ -117,7 +136,7 @@
                     rank, count, true);
 
             if (DEBUG) Log.d(TAG, "Clearing notification, key: " + notifKey + ", rank: " + rank);
-            statusBarService.onNotificationClear(
+            mIStatusBarService.onNotificationClear(
                     packageName, userHandle.getIdentifier(), notifKey,
                     NotificationStats.DISMISSAL_OTHER,
                     NotificationStats.DISMISS_SENTIMENT_POSITIVE, notifVisibility);
@@ -125,4 +144,10 @@
             Log.e(TAG, "Exception cancelling notification:" + e);
         }
     }
+
+    @VisibleForTesting
+    void setIsForTesting(boolean isForTesting, IStatusBarService statusBarService) {
+        mIsForTesting = isForTesting;
+        mIStatusBarService = statusBarService;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
index 30eb2ac..4ad685e 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
@@ -22,11 +22,13 @@
 import static com.android.systemui.people.PeopleSpaceUtils.SHORTCUT_ID;
 import static com.android.systemui.people.PeopleSpaceUtils.USER_ID;
 import static com.android.systemui.people.PeopleSpaceUtils.augmentTileFromNotification;
-import static com.android.systemui.people.PeopleSpaceUtils.getPeopleSpaceTile;
 import static com.android.systemui.people.PeopleSpaceUtils.getStoredWidgetIds;
 import static com.android.systemui.people.PeopleSpaceUtils.updateAppWidgetOptionsAndView;
+import static com.android.systemui.people.PeopleSpaceUtils.updateAppWidgetViews;
 
+import android.annotation.Nullable;
 import android.app.NotificationChannel;
+import android.app.PendingIntent;
 import android.app.Person;
 import android.app.people.ConversationChannel;
 import android.app.people.IPeopleManager;
@@ -43,18 +45,20 @@
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.preference.PreferenceManager;
-import android.provider.Settings;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.StatusBarNotification;
 import android.util.Log;
+import android.widget.RemoteViews;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.UiEventLoggerImpl;
+import com.android.systemui.Dependency;
 import com.android.systemui.people.PeopleSpaceUtils;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
 
 import java.util.Collections;
 import java.util.HashMap;
@@ -78,6 +82,7 @@
     private IPeopleManager mIPeopleManager;
     private SharedPreferences mSharedPrefs;
     private PeopleManager mPeopleManager;
+    private NotificationEntryManager mNotificationEntryManager;
     public UiEventLogger mUiEventLogger = new UiEventLoggerImpl();
     @GuardedBy("mLock")
     public static Map<PeopleTileKey, PeopleSpaceWidgetProvider.TileConversationListener>
@@ -93,6 +98,7 @@
         mLauncherApps = context.getSystemService(LauncherApps.class);
         mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(mContext);
         mPeopleManager = mContext.getSystemService(PeopleManager.class);
+        mNotificationEntryManager = Dependency.get(NotificationEntryManager.class);
     }
 
     /**
@@ -101,11 +107,13 @@
     @VisibleForTesting
     protected void setAppWidgetManager(
             AppWidgetManager appWidgetManager, IPeopleManager iPeopleManager,
-            PeopleManager peopleManager, LauncherApps launcherApps) {
+            PeopleManager peopleManager, LauncherApps launcherApps,
+            NotificationEntryManager notificationEntryManager) {
         mAppWidgetManager = appWidgetManager;
         mIPeopleManager = iPeopleManager;
         mPeopleManager = peopleManager;
         mLauncherApps = launcherApps;
+        mNotificationEntryManager = notificationEntryManager;
     }
 
     /**
@@ -120,13 +128,8 @@
             }
 
             if (DEBUG) Log.d(TAG, "updating " + widgetIds.length + " widgets");
-            boolean showSingleConversation = Settings.Global.getInt(mContext.getContentResolver(),
-                    Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 0;
-            if (showSingleConversation) {
-                synchronized (mLock) {
-                    PeopleSpaceUtils.updateSingleConversationWidgets(
-                            mContext, widgetIds, mAppWidgetManager, mIPeopleManager);
-                }
+            synchronized (mLock) {
+                updateSingleConversationWidgets(widgetIds);
             }
         } catch (Exception e) {
             Log.e(TAG, "Exception: " + e);
@@ -134,17 +137,91 @@
     }
 
     /**
+     * Updates {@code appWidgetIds} with their associated conversation stored, handling a
+     * notification being posted or removed.
+     */
+    public void updateSingleConversationWidgets(int[] appWidgetIds) {
+        Map<Integer, PeopleSpaceTile> widgetIdToTile = new HashMap<>();
+        for (int appWidgetId : appWidgetIds) {
+            PeopleSpaceTile tile = getTileForExistingWidget(appWidgetId);
+            if (tile == null) {
+                if (DEBUG) Log.d(TAG, "Matching conversation not found for shortcut ID");
+                //TODO: Delete app widget id when crash is fixed (b/172932636)
+                continue;
+            }
+            Bundle options = mAppWidgetManager.getAppWidgetOptions(appWidgetId);
+            updateAppWidgetViews(mAppWidgetManager, mContext, appWidgetId, tile, options);
+            widgetIdToTile.put(appWidgetId, tile);
+        }
+        PeopleSpaceUtils.getBirthdaysOnBackgroundThread(
+                mContext, mAppWidgetManager, widgetIdToTile, appWidgetIds);
+    }
+
+    /**
+     * Returns a {@link PeopleSpaceTile} based on the {@code appWidgetId}.
+     * Widget already exists, so fetch {@link PeopleTileKey} from {@link SharedPreferences}.
+     */
+    @Nullable
+    public PeopleSpaceTile getTileForExistingWidget(int appWidgetId) {
+        // First, check if tile is cached in AppWidgetOptions.
+        PeopleSpaceTile tile = AppWidgetOptionsHelper.getPeopleTile(mAppWidgetManager, appWidgetId);
+        if (tile != null) {
+            if (DEBUG) Log.d(TAG, "People Tile is cached for widget: " + appWidgetId);
+            return tile;
+        }
+
+        // If tile is null, we need to retrieve from persistent storage.
+        if (DEBUG) Log.d(TAG, "Fetching key from sharedPreferences: " + appWidgetId);
+        SharedPreferences widgetSp = mContext.getSharedPreferences(
+                String.valueOf(appWidgetId),
+                Context.MODE_PRIVATE);
+        PeopleTileKey key = new PeopleTileKey(
+                widgetSp.getString(SHORTCUT_ID, EMPTY_STRING),
+                widgetSp.getInt(USER_ID, INVALID_USER_ID),
+                widgetSp.getString(PACKAGE_NAME, EMPTY_STRING));
+
+        return getTileFromPersistentStorage(key);
+    }
+
+    /**
+     * Returns a {@link PeopleSpaceTile} based on the {@code appWidgetId}.
+     * If a {@link PeopleTileKey} is not provided, fetch one from {@link SharedPreferences}.
+     */
+    @Nullable
+    public PeopleSpaceTile getTileFromPersistentStorage(PeopleTileKey key) {
+        if (!key.isValid()) {
+            Log.e(TAG, "PeopleTileKey invalid: " + key);
+            return null;
+        }
+
+        if (mIPeopleManager == null || mLauncherApps == null) {
+            Log.d(TAG, "System services are null");
+            return null;
+        }
+
+        try {
+            if (DEBUG) Log.d(TAG, "Retrieving Tile from storage: " + key.toString());
+            ConversationChannel channel = mIPeopleManager.getConversation(
+                    key.getPackageName(), key.getUserId(), key.getShortcutId());
+            if (channel == null) {
+                Log.d(TAG, "Could not retrieve conversation from storage");
+                return null;
+            }
+
+            return new PeopleSpaceTile.Builder(channel, mLauncherApps).build();
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to retrieve conversation for tile: " + e);
+            return null;
+        }
+    }
+
+    /**
      * Check if any existing People tiles match the incoming notification change, and store the
      * change in the tile if so.
      */
     public void updateWidgetsWithNotificationChanged(StatusBarNotification sbn,
             PeopleSpaceUtils.NotificationAction notificationAction) {
         if (DEBUG) Log.d(TAG, "updateWidgetsWithNotificationChanged called");
-        boolean showSingleConversation = Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 0;
-        if (!showSingleConversation) {
-            return;
-        }
         try {
             String sbnShortcutId = sbn.getShortcutId();
             if (sbnShortcutId == null) {
@@ -201,8 +278,7 @@
      */
     private void updateStorageAndViewWithConversationData(ConversationChannel conversation,
             int appWidgetId) {
-        PeopleSpaceTile storedTile = getPeopleSpaceTile(
-                mContext, appWidgetId, mAppWidgetManager, mIPeopleManager);
+        PeopleSpaceTile storedTile = getTileForExistingWidget(appWidgetId);
         if (storedTile == null) {
             if (DEBUG) Log.d(TAG, "Could not find stored tile to add conversation to");
             return;
@@ -234,8 +310,7 @@
             StatusBarNotification sbn,
             PeopleSpaceUtils.NotificationAction notificationAction,
             int appWidgetId) {
-        PeopleSpaceTile storedTile = getPeopleSpaceTile(
-                mContext, appWidgetId, mAppWidgetManager, mIPeopleManager);
+        PeopleSpaceTile storedTile = getTileForExistingWidget(appWidgetId);
         if (storedTile == null) {
             if (DEBUG) Log.d(TAG, "Could not find stored tile to add notification to");
             return;
@@ -332,28 +407,51 @@
                 Log.d(TAG, "PeopleTileKey was present in Options, shortcutId: "
                         + optionsKey.getShortcutId());
             }
-            addNewWidget(appWidgetId, optionsKey);
             AppWidgetOptionsHelper.removePeopleTileKey(mAppWidgetManager, appWidgetId);
+            addNewWidget(appWidgetId, optionsKey);
         }
         // Update views for new widget dimensions.
         updateWidgets(new int[]{appWidgetId});
     }
 
-    /** Adds{@code tile} mapped to {@code appWidgetId}. */
+    /** Adds a widget based on {@code key} mapped to {@code appWidgetId}. */
     public void addNewWidget(int appWidgetId, PeopleTileKey key) {
+        if (DEBUG) Log.d(TAG, "addNewWidget called with key for appWidgetId: " + appWidgetId);
+        PeopleSpaceTile tile = getTileFromPersistentStorage(key);
+        tile = PeopleSpaceUtils.augmentSingleTileFromVisibleNotifications(
+                mContext, tile, mNotificationEntryManager);
+        if (tile != null) {
+            addNewWidget(appWidgetId, tile);
+        }
+    }
+
+    /**
+     * Adds a widget based on {@code tile} mapped to {@code appWidgetId}.
+     * The tile provided should already be augmented.
+     */
+    public void addNewWidget(int appWidgetId, PeopleSpaceTile tile) {
+        if (DEBUG) Log.d(TAG, "addNewWidget called for appWidgetId: " + appWidgetId);
+        if (tile == null) {
+            return;
+        }
+
         mUiEventLogger.log(PeopleSpaceUtils.PeopleSpaceWidgetEvent.PEOPLE_SPACE_WIDGET_ADDED);
         synchronized (mLock) {
-            if (DEBUG) Log.d(TAG, "Add storage for : " + key.getShortcutId());
+            if (DEBUG) Log.d(TAG, "Add storage for : " + tile.getId());
+            PeopleTileKey key = new PeopleTileKey(tile);
             PeopleSpaceUtils.setSharedPreferencesStorageForTile(mContext, key, appWidgetId);
         }
         try {
-            if (DEBUG) Log.d(TAG, "Caching shortcut for PeopleTile: " + key.getShortcutId());
-            mLauncherApps.cacheShortcuts(key.getPackageName(),
-                    Collections.singletonList(key.getShortcutId()),
-                    UserHandle.of(key.getUserId()), LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS);
+            if (DEBUG) Log.d(TAG, "Caching shortcut for PeopleTile: " + tile.getId());
+            mLauncherApps.cacheShortcuts(tile.getPackageName(),
+                    Collections.singletonList(tile.getId()),
+                    tile.getUserHandle(), LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS);
         } catch (Exception e) {
             Log.w(TAG, "Exception caching shortcut:" + e);
         }
+
+        PeopleSpaceUtils.updateAppWidgetOptionsAndView(
+                mAppWidgetManager, mContext, appWidgetId, tile);
         PeopleSpaceWidgetProvider provider = new PeopleSpaceWidgetProvider();
         provider.onUpdate(mContext, mAppWidgetManager, new int[]{appWidgetId});
     }
@@ -452,4 +550,28 @@
             Log.d(TAG, "Exception uncaching shortcut:" + e);
         }
     }
+
+    /**
+     * Builds a request to pin a People Tile app widget, with a preview and storing necessary
+     * information as the callback.
+     */
+    public boolean requestPinAppWidget(ShortcutInfo shortcutInfo) {
+        if (DEBUG) Log.d(TAG, "Requesting pin widget, shortcutId: " + shortcutInfo.getId());
+
+        RemoteViews widgetPreview = PeopleSpaceUtils.getPreview(mContext, mIPeopleManager,
+                mLauncherApps, mNotificationEntryManager, shortcutInfo.getId(),
+                shortcutInfo.getUserHandle(), shortcutInfo.getPackage());
+        if (widgetPreview == null) {
+            Log.w(TAG, "Skipping pinning widget: no tile for shortcutId: " + shortcutInfo.getId());
+            return false;
+        }
+        Bundle extras = new Bundle();
+        extras.putParcelable(AppWidgetManager.EXTRA_APPWIDGET_PREVIEW, widgetPreview);
+
+        PendingIntent successCallback =
+                PeopleSpaceWidgetPinnedReceiver.getPendingIntent(mContext, shortcutInfo);
+
+        ComponentName componentName = new ComponentName(mContext, PeopleSpaceWidgetProvider.class);
+        return mAppWidgetManager.requestPinAppWidget(componentName, extras, successCallback);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetPinnedReceiver.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetPinnedReceiver.java
new file mode 100644
index 0000000..a28da43
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetPinnedReceiver.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 com.android.systemui.people.widget;
+
+import static com.android.systemui.people.PeopleSpaceUtils.INVALID_USER_ID;
+
+import android.app.PendingIntent;
+import android.appwidget.AppWidgetManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ShortcutInfo;
+import android.util.Log;
+
+import com.android.systemui.people.PeopleSpaceUtils;
+
+import javax.inject.Inject;
+
+/** Called when a People Tile widget is added via {@link AppWidgetManager.requestPinAppWidget()}. */
+public class PeopleSpaceWidgetPinnedReceiver extends BroadcastReceiver {
+    private static final String TAG = "PeopleSpaceWgtPinReceiver";
+    private static final int BROADCAST_ID = 0;
+    private static final int INVALID_WIDGET_ID = -1;
+    private static final boolean DEBUG = PeopleSpaceUtils.DEBUG;
+
+    private final PeopleSpaceWidgetManager mPeopleSpaceWidgetManager;
+
+    @Inject
+    public PeopleSpaceWidgetPinnedReceiver(PeopleSpaceWidgetManager peopleSpaceWidgetManager) {
+        mPeopleSpaceWidgetManager = peopleSpaceWidgetManager;
+    }
+
+    /** Creates a {@link PendingIntent} that is passed onto this receiver when a widget is added. */
+    public static PendingIntent getPendingIntent(Context context, ShortcutInfo shortcutInfo) {
+        Intent intent = new Intent(context, PeopleSpaceWidgetPinnedReceiver.class)
+                .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+        intent.putExtra(Intent.EXTRA_SHORTCUT_ID, shortcutInfo.getId());
+        intent.putExtra(Intent.EXTRA_USER_ID, shortcutInfo.getUserId());
+        intent.putExtra(Intent.EXTRA_PACKAGE_NAME, shortcutInfo.getPackage());
+
+        // Intent needs to be mutable because App Widget framework populates it with app widget id.
+        return PendingIntent.getBroadcast(context, BROADCAST_ID, intent,
+                PendingIntent.FLAG_MUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if (DEBUG) Log.d(TAG, "Add widget broadcast received");
+        if (context == null || intent == null) {
+            if (DEBUG) Log.w(TAG, "Skipping: context or intent are null");
+            return;
+        }
+
+        int widgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, INVALID_WIDGET_ID);
+        if (widgetId == INVALID_WIDGET_ID) {
+            if (DEBUG) Log.w(TAG, "Skipping: invalid widgetId");
+            return;
+        }
+
+        String shortcutId = intent.getStringExtra(Intent.EXTRA_SHORTCUT_ID);
+        String packageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
+        int userId = intent.getIntExtra(Intent.EXTRA_USER_ID, INVALID_USER_ID);
+        PeopleTileKey key = new PeopleTileKey(shortcutId, userId, packageName);
+        if (!key.isValid()) {
+            if (DEBUG) Log.w(TAG, "Skipping: key is not valid: " + key.toString());
+            return;
+        }
+
+        if (DEBUG) Log.d(TAG, "Adding widget: " + widgetId + ", key:" + key.toString());
+        mPeopleSpaceWidgetManager.addNewWidget(widgetId, key);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java
deleted file mode 100644
index 87b2a15..0000000
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java
+++ /dev/null
@@ -1,154 +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.systemui.people.widget;
-
-import android.app.INotificationManager;
-import android.app.people.IPeopleManager;
-import android.app.people.PeopleSpaceTile;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.LauncherApps;
-import android.content.pm.PackageManager;
-import android.os.ServiceManager;
-import android.util.Log;
-import android.widget.RemoteViews;
-import android.widget.RemoteViewsService;
-
-import com.android.systemui.Dependency;
-import com.android.systemui.R;
-import com.android.systemui.people.PeopleSpaceTileView;
-import com.android.systemui.people.PeopleSpaceUtils;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/** People Space Widget RemoteViewsFactory class. */
-public class PeopleSpaceWidgetRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
-    private static final String TAG = "PeopleSpaceWRVFactory";
-    private static final boolean DEBUG = PeopleSpaceUtils.DEBUG;
-
-    private IPeopleManager mPeopleManager;
-    private INotificationManager mNotificationManager;
-    private NotificationEntryManager mNotificationEntryManager;
-    private PackageManager mPackageManager;
-    private LauncherApps mLauncherApps;
-    private List<PeopleSpaceTile> mTiles = new ArrayList<>();
-    private Context mContext;
-
-    public PeopleSpaceWidgetRemoteViewsFactory(Context context, Intent intent) {
-        this.mContext = context;
-    }
-
-    @Override
-    public void onCreate() {
-        if (DEBUG) Log.d(TAG, "onCreate called");
-        mNotificationManager = INotificationManager.Stub.asInterface(
-                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
-        mNotificationEntryManager = Dependency.get(NotificationEntryManager.class);
-        mPackageManager = mContext.getPackageManager();
-        mPeopleManager = IPeopleManager.Stub.asInterface(
-                ServiceManager.getService(Context.PEOPLE_SERVICE));
-        mLauncherApps = mContext.getSystemService(LauncherApps.class);
-        setTileViewsWithPriorityConversations();
-    }
-
-    /**
-     * Retrieves all priority conversations and sets a {@link PeopleSpaceTileView}s for each
-     * priority conversation.
-     */
-    private void setTileViewsWithPriorityConversations() {
-        try {
-            mTiles = PeopleSpaceUtils.getTiles(mContext, mNotificationManager,
-                    mPeopleManager, mLauncherApps, mNotificationEntryManager);
-        } catch (Exception e) {
-            Log.e(TAG, "Couldn't retrieve conversations", e);
-        }
-    }
-
-    @Override
-    public void onDataSetChanged() {
-        if (DEBUG) Log.d(TAG, "onDataSetChanged called");
-        setTileViewsWithPriorityConversations();
-    }
-
-    @Override
-    public void onDestroy() {
-        mTiles.clear();
-    }
-
-    @Override
-    public int getCount() {
-        return mTiles.size();
-    }
-
-    @Override
-    public RemoteViews getViewAt(int i) {
-        if (DEBUG) Log.d(TAG, "getViewAt called, index: " + i);
-
-        RemoteViews personView = new RemoteViews(mContext.getPackageName(),
-                R.layout.people_space_widget_item);
-        try {
-            PeopleSpaceTile tile = mTiles.get(i);
-
-            String status = PeopleSpaceUtils.getLastInteractionString(mContext,
-                    tile.getLastInteractionTimestamp());
-
-            personView.setTextViewText(R.id.status, status);
-            personView.setTextViewText(R.id.name, tile.getUserName().toString());
-
-            personView.setImageViewBitmap(
-                    R.id.package_icon,
-                    PeopleSpaceUtils.convertDrawableToBitmap(
-                            mPackageManager.getApplicationIcon(tile.getPackageName())
-                    )
-            );
-            personView.setImageViewIcon(R.id.person_icon, tile.getUserIcon());
-
-            Intent fillInIntent = new Intent();
-            fillInIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_TILE_ID, tile.getId());
-            fillInIntent.putExtra(
-                    PeopleSpaceWidgetProvider.EXTRA_PACKAGE_NAME, tile.getPackageName());
-            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);
-        }
-        return personView;
-    }
-
-    @Override
-    public RemoteViews getLoadingView() {
-        return null;
-    }
-
-    @Override
-    public int getViewTypeCount() {
-        return 1;
-    }
-
-    @Override
-    public long getItemId(int i) {
-        return i;
-    }
-
-    @Override
-    public boolean hasStableIds() {
-        return true;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetService.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetService.java
deleted file mode 100644
index c0e4347..0000000
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetService.java
+++ /dev/null
@@ -1,34 +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.systemui.people.widget;
-import android.content.Intent;
-import android.util.Log;
-import android.widget.RemoteViewsService;
-
-import com.android.systemui.people.PeopleSpaceUtils;
-
-/** People Space Widget Service class. */
-public class PeopleSpaceWidgetService extends RemoteViewsService {
-    private static final String TAG = "PeopleSpaceWidgetSvc";
-    private static final boolean DEBUG = PeopleSpaceUtils.DEBUG;
-
-    @Override
-    public RemoteViewsFactory onGetViewFactory(Intent intent) {
-        if (DEBUG) Log.d(TAG, "onGetViewFactory called");
-        return new PeopleSpaceWidgetRemoteViewsFactory(this.getApplicationContext(), intent);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleTileKey.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleTileKey.java
index ac42cb0..319df85 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleTileKey.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleTileKey.java
@@ -19,6 +19,7 @@
 import static com.android.systemui.people.PeopleSpaceUtils.EMPTY_STRING;
 import static com.android.systemui.people.PeopleSpaceUtils.INVALID_USER_ID;
 
+import android.app.people.PeopleSpaceTile;
 import android.text.TextUtils;
 
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -37,6 +38,12 @@
         mPackageName = packageName;
     }
 
+    public PeopleTileKey(PeopleSpaceTile tile) {
+        mShortcutId = tile.getId();
+        mUserId = tile.getUserHandle().getIdentifier();
+        mPackageName = tile.getPackageName();
+    }
+
     public PeopleTileKey(NotificationEntry entry) {
         mShortcutId = entry.getRanking() != null
                 && entry.getRanking().getConversationShortcutInfo() != null
@@ -81,7 +88,7 @@
      */
     @Override
     public String toString() {
-        if (!isValid()) return null;
+        if (!isValid()) return EMPTY_STRING;
         return mShortcutId + "/" + mUserId + "/" + mPackageName;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index 8ab1743..6386365 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -67,6 +67,7 @@
     private final DumpManager mDumpManager;
     private final FeatureFlags mFeatureFlags;
     protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
+    private boolean mShouldUseSplitNotificationShade;
 
     private int mLastOrientation;
     private String mCachedSpecs = "";
@@ -81,6 +82,8 @@
             new QSPanel.OnConfigurationChangedListener() {
                 @Override
                 public void onConfigurationChange(Configuration newConfig) {
+                    mShouldUseSplitNotificationShade =
+                            Utils.shouldUseSplitNotificationShade(mFeatureFlags, getResources());
                     if (newConfig.orientation != mLastOrientation) {
                         mLastOrientation = newConfig.orientation;
                         switchTileLayout(false);
@@ -119,6 +122,8 @@
         mDumpManager = dumpManager;
         mFeatureFlags = featureFlags;
         mQSLabelFlag = featureFlags.isQSLabelsEnabled();
+        mShouldUseSplitNotificationShade =
+                Utils.shouldUseSplitNotificationShade(mFeatureFlags, getResources());
     }
 
     @Override
@@ -345,7 +350,7 @@
     }
 
     boolean shouldUseHorizontalLayout() {
-        if (Utils.shouldUseSplitNotificationShade(mFeatureFlags, getResources()))  {
+        if (mShouldUseSplitNotificationShade)  {
             return false;
         }
         return mUsingMediaPlayer && mMediaHost.getVisible()
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index 29b9e64..ba349c6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -47,6 +47,7 @@
 import com.android.systemui.qs.tiles.MicrophoneToggleTile;
 import com.android.systemui.qs.tiles.NfcTile;
 import com.android.systemui.qs.tiles.NightDisplayTile;
+import com.android.systemui.qs.tiles.QuickAccessWalletTile;
 import com.android.systemui.qs.tiles.ReduceBrightColorsTile;
 import com.android.systemui.qs.tiles.RotationLockTile;
 import com.android.systemui.qs.tiles.ScreenRecordTile;
@@ -93,6 +94,7 @@
     private final Provider<MicrophoneToggleTile> mMicrophoneToggleTileProvider;
     private final Provider<DeviceControlsTile> mDeviceControlsTileProvider;
     private final Provider<AlarmTile> mAlarmTileProvider;
+    private final Provider<QuickAccessWalletTile> mQuickAccessWalletTileProvider;
 
     private final Lazy<QSHost> mQsHostLazy;
     private final Provider<CustomTile.Builder> mCustomTileBuilderProvider;
@@ -129,7 +131,8 @@
             Provider<CameraToggleTile> cameraToggleTileProvider,
             Provider<MicrophoneToggleTile> microphoneToggleTileProvider,
             Provider<DeviceControlsTile> deviceControlsTileProvider,
-            Provider<AlarmTile> alarmTileProvider) {
+            Provider<AlarmTile> alarmTileProvider,
+            Provider<QuickAccessWalletTile> quickAccessWalletTileProvider) {
         mQsHostLazy = qsHostLazy;
         mCustomTileBuilderProvider = customTileBuilderProvider;
 
@@ -161,6 +164,7 @@
         mMicrophoneToggleTileProvider = microphoneToggleTileProvider;
         mDeviceControlsTileProvider = deviceControlsTileProvider;
         mAlarmTileProvider = alarmTileProvider;
+        mQuickAccessWalletTileProvider = quickAccessWalletTileProvider;
     }
 
     public QSTile createTile(String tileSpec) {
@@ -224,6 +228,8 @@
                 return mDeviceControlsTileProvider.get();
             case "alarm":
                 return mAlarmTileProvider.get();
+            case "wallet":
+                return mQuickAccessWalletTileProvider.get();
         }
 
         // Custom tiles
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
new file mode 100644
index 0000000..60c5d1c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
@@ -0,0 +1,136 @@
+/*
+ * 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.tiles;
+
+import static android.provider.Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT;
+
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.service.quickaccesswallet.QuickAccessWalletClient;
+import android.service.quicksettings.Tile;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
+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.logging.QSLogger;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.settings.SecureSettings;
+
+import javax.inject.Inject;
+
+/** Quick settings tile: Quick access wallet **/
+public class QuickAccessWalletTile extends QSTileImpl<QSTile.State> {
+
+    private static final String FEATURE_CHROME_OS = "org.chromium.arc";
+    private final CharSequence mLabel = mContext.getString(R.string.wallet_title);
+    // TODO(b/180959290): Re-create the QAW Client when the default NFC payment app changes.
+    private final QuickAccessWalletClient mQuickAccessWalletClient;
+    private final KeyguardStateController mKeyguardStateController;
+    private final PackageManager mPackageManager;
+    private final SecureSettings mSecureSettings;
+    private final FeatureFlags mFeatureFlags;
+
+    @Inject
+    public QuickAccessWalletTile(
+            QSHost host,
+            @Background Looper backgroundLooper,
+            @Main Handler mainHandler,
+            FalsingManager falsingManager,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger,
+            QuickAccessWalletClient quickAccessWalletClient,
+            KeyguardStateController keyguardStateController,
+            PackageManager packageManager,
+            SecureSettings secureSettings,
+            FeatureFlags featureFlags) {
+        super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger);
+        mQuickAccessWalletClient = quickAccessWalletClient;
+        mKeyguardStateController = keyguardStateController;
+        mPackageManager = packageManager;
+        mSecureSettings = secureSettings;
+        mFeatureFlags = featureFlags;
+    }
+
+
+    @Override
+    public State newTileState() {
+        State state = new State();
+        state.handlesLongClick = false;
+        return state;
+    }
+
+    @Override
+    protected void handleClick() {
+        mActivityStarter.postStartActivityDismissingKeyguard(
+                mQuickAccessWalletClient.createWalletIntent(), /* delay= */ 0);
+    }
+
+    @Override
+    protected void handleUpdateState(State state, Object arg) {
+        CharSequence qawLabel = mQuickAccessWalletClient.getServiceLabel();
+        state.label = qawLabel == null ? mLabel : qawLabel;
+        state.contentDescription = state.label;
+        state.icon = ResourceIcon.get(R.drawable.ic_qs_wallet);
+        boolean isDeviceLocked = !mKeyguardStateController.isUnlocked();
+        if (mQuickAccessWalletClient.isWalletFeatureAvailable()) {
+            state.state = isDeviceLocked ? Tile.STATE_INACTIVE : Tile.STATE_ACTIVE;
+            state.secondaryLabel = isDeviceLocked
+                    ? null
+                    : mContext.getString(R.string.wallet_secondary_label);
+            state.stateDescription = state.secondaryLabel;
+        } else {
+            state.state = Tile.STATE_UNAVAILABLE;
+        }
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return 0;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return mFeatureFlags.isQuickAccessWalletEnabled()
+                && mPackageManager.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)
+                && !mPackageManager.hasSystemFeature(FEATURE_CHROME_OS)
+                && mSecureSettings.getString(NFC_PAYMENT_DEFAULT_COMPONENT) != null;
+    }
+
+    @Override
+    public Intent getLongClickIntent() {
+        return null;
+    }
+
+    @Override
+    public CharSequence getTileLabel() {
+        CharSequence qawLabel = mQuickAccessWalletClient.getServiceLabel();
+        return qawLabel == null ? mLabel : qawLabel;
+    }
+}
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 479be65..03a6689 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
@@ -25,8 +25,8 @@
 import android.service.quicksettings.Tile;
 import android.widget.Switch;
 
+import com.android.internal.R;
 import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.R;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
@@ -98,14 +98,14 @@
 
     @Override
     public CharSequence getTileLabel() {
-        return mContext.getString(R.string.quick_settings_reduce_bright_colors_label);
+        return mContext.getString(R.string.reduce_bright_colors_feature_name);
     }
 
     @Override
     protected void handleUpdateState(BooleanState state, Object arg) {
         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.label = mContext.getString(R.string.reduce_bright_colors_feature_name);
         state.expandedAccessibilityClassName = Switch.class.getName();
         state.contentDescription = state.label;
     }
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 dab68ed..86ea50c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -177,8 +177,10 @@
             }
         }
         boolean transientEnabling = arg == ARG_SHOW_TRANSIENT_ENABLING;
-        boolean wifiConnected = cb.enabled && (cb.wifiSignalIconId > 0) && (cb.ssid != null);
-        boolean wifiNotConnected = (cb.wifiSignalIconId > 0) && (cb.ssid == null);
+        boolean wifiConnected = cb.enabled && (cb.wifiSignalIconId > 0)
+                && (cb.ssid != null || cb.wifiSignalIconId != WifiIcons.QS_WIFI_NO_NETWORK);
+        boolean wifiNotConnected = (cb.ssid == null)
+                && (cb.wifiSignalIconId == WifiIcons.QS_WIFI_NO_NETWORK);
         boolean enabledChanging = state.value != cb.enabled;
         if (enabledChanging) {
             mDetailAdapter.setItemsVisible(cb.enabled);
@@ -210,7 +212,7 @@
             state.label = r.getString(R.string.quick_settings_wifi_label);
         } else if (wifiConnected) {
             state.icon = ResourceIcon.get(cb.wifiSignalIconId);
-            state.label = removeDoubleQuotes(cb.ssid);
+            state.label = cb.ssid != null ? removeDoubleQuotes(cb.ssid) : getTileLabel();
         } else if (wifiNotConnected) {
             state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_NO_NETWORK);
             state.label = r.getString(R.string.quick_settings_wifi_label);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 8951605..b0a3f43 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -25,6 +25,11 @@
 
 import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR;
+import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_ONE_HANDED;
+import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_PIP;
+import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS;
+import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SPLIT_SCREEN;
+import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_STARTING_WINDOW;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SUPPORTS_WINDOW_CORNERS;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WINDOW_CORNER_RADIUS;
@@ -35,15 +40,12 @@
 
 import android.annotation.FloatRange;
 import android.app.ActivityTaskManager;
-import android.app.PendingIntent;
-import android.app.PictureInPictureParams;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
-import android.content.pm.ActivityInfo;
 import android.graphics.Bitmap;
 import android.graphics.Insets;
 import android.graphics.Rect;
@@ -57,14 +59,12 @@
 import android.os.PatternMatcher;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.util.ArraySet;
 import android.util.Log;
 import android.view.InputMonitor;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.accessibility.AccessibilityManager;
-import android.window.IRemoteTransition;
 
 import androidx.annotation.NonNull;
 
@@ -83,15 +83,11 @@
 import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
 import com.android.systemui.settings.CurrentUserTracker;
 import com.android.systemui.shared.recents.IOverviewProxy;
-import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
-import com.android.systemui.shared.recents.ISplitScreenListener;
-import com.android.systemui.shared.recents.IStartingWindowListener;
 import com.android.systemui.shared.recents.ISystemUiProxy;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.InputMonitorCompat;
 import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.shared.system.RemoteTransitionCompat;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.phone.StatusBar;
@@ -103,7 +99,7 @@
 import com.android.wm.shell.pip.PipAnimationController;
 import com.android.wm.shell.splitscreen.SplitScreen;
 import com.android.wm.shell.startingsurface.StartingSurface;
-import com.android.wm.shell.transition.RemoteTransitions;
+import com.android.wm.shell.transition.ShellTransitions;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -111,7 +107,6 @@
 import java.util.List;
 import java.util.Optional;
 import java.util.function.BiConsumer;
-import java.util.function.Consumer;
 
 import javax.inject.Inject;
 
@@ -151,12 +146,11 @@
     private final ScreenshotHelper mScreenshotHelper;
     private final Optional<OneHanded> mOneHandedOptional;
     private final CommandQueue mCommandQueue;
-    private final RemoteTransitions mShellTransitions;
+    private final ShellTransitions mShellTransitions;
     private final Optional<StartingSurface> mStartingSurface;
 
     private Region mActiveNavBarRegion;
 
-    private IPinnedStackAnimationListener mIPinnedStackAnimationListener;
     private IOverviewProxy mOverviewProxy;
     private int mConnectionBackoffAttempts;
     private boolean mBound;
@@ -169,8 +163,6 @@
     private float mWindowCornerRadius;
     private boolean mSupportsRoundedCornersOnWindows;
     private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
-    private final ArraySet<IRemoteTransition> mRemoteTransitions = new ArraySet<>();
-    private IStartingWindowListener mIStartingWindowListener;
 
     @VisibleForTesting
     public ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
@@ -383,20 +375,6 @@
         }
 
         @Override
-        public void setShelfHeight(boolean visible, int shelfHeight) {
-            if (!verifyCaller("setShelfHeight")) {
-                return;
-            }
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mPipOptional.ifPresent(
-                        pip -> pip.setShelfHeight(visible, shelfHeight));
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
         public void handleImageAsScreenshot(Bitmap screenImage, Rect locationInScreen,
                 Insets visibleInsets, int taskId) {
             // Deprecated
@@ -424,36 +402,6 @@
         }
 
         @Override
-        public void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) {
-            if (!verifyCaller("setPinnedStackAnimationListener")) {
-                return;
-            }
-            mIPinnedStackAnimationListener = listener;
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mPipOptional.ifPresent(
-                        pip -> pip.setPinnedStackAnimationListener(mPinnedStackAnimationCallback));
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void setStartingWindowListener(IStartingWindowListener listener) {
-            if (!verifyCaller("setStartingWindowListener")) {
-                return;
-            }
-            mIStartingWindowListener = listener;
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mStartingSurface.ifPresent(s ->
-                        s.setStartingWindowListener(mStartingWindowListener));
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
         public void onQuickSwitchToNewTask(@Surface.Rotation int rotation) {
             if (!verifyCaller("onQuickSwitchToNewTask")) {
                 return;
@@ -467,32 +415,6 @@
         }
 
         @Override
-        public void startOneHandedMode() {
-            if (!verifyCaller("startOneHandedMode")) {
-                return;
-            }
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mOneHandedOptional.ifPresent(oneHanded -> oneHanded.startOneHanded());
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void stopOneHandedMode()  {
-            if (!verifyCaller("stopOneHandedMode")) {
-                return;
-            }
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mOneHandedOptional.ifPresent(oneHanded -> oneHanded.stopOneHanded());
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
         public void handleImageBundleAsScreenshot(Bundle screenImageBundle, Rect locationInScreen,
                 Insets visibleInsets, Task.TaskKey task) {
             mScreenshotHelper.provideScreenshot(
@@ -520,190 +442,6 @@
             }
         }
 
-        @Override
-        public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
-                PictureInPictureParams pictureInPictureParams,
-                int launcherRotation, int shelfHeight) {
-            if (!verifyCaller("startSwipePipToHome")) {
-                return null;
-            }
-            final long binderToken = Binder.clearCallingIdentity();
-            try {
-                return mPipOptional.map(pip ->
-                        pip.startSwipePipToHome(componentName, activityInfo,
-                                pictureInPictureParams, launcherRotation, shelfHeight))
-                        .orElse(null);
-            } finally {
-                Binder.restoreCallingIdentity(binderToken);
-            }
-        }
-
-        @Override
-        public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) {
-            if (!verifyCaller("stopSwipePipToHome")) {
-                return;
-            }
-            final long binderToken = Binder.clearCallingIdentity();
-            try {
-                mPipOptional.ifPresent(pip -> pip.stopSwipePipToHome(
-                        componentName, destinationBounds));
-            } finally {
-                Binder.restoreCallingIdentity(binderToken);
-            }
-        }
-
-        @Override
-        public void registerRemoteTransition(RemoteTransitionCompat remoteTransition) {
-            if (!verifyCaller("registerRemoteTransition")) return;
-            final long binderToken = Binder.clearCallingIdentity();
-            try {
-                mRemoteTransitions.add(remoteTransition.getTransition());
-                mShellTransitions.registerRemote(
-                        remoteTransition.getFilter(), remoteTransition.getTransition());
-            } finally {
-                Binder.restoreCallingIdentity(binderToken);
-            }
-        }
-
-        @Override
-        public void unregisterRemoteTransition(RemoteTransitionCompat remoteTransition) {
-            if (!verifyCaller("registerRemoteTransition")) return;
-            final long binderToken = Binder.clearCallingIdentity();
-            try {
-                mRemoteTransitions.remove(remoteTransition.getTransition());
-                mShellTransitions.unregisterRemote(remoteTransition.getTransition());
-            } finally {
-                Binder.restoreCallingIdentity(binderToken);
-            }
-        }
-
-        @Override
-        public void registerSplitScreenListener(ISplitScreenListener listener) {
-            if (!verifyCaller("registerSplitScreenListener")) {
-                return;
-            }
-            mISplitScreenListener = listener;
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mSplitScreenOptional.ifPresent(
-                        s -> s.registerSplitScreenListener(mSplitScreenListener));
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void unregisterSplitScreenListener(ISplitScreenListener listener) {
-            if (!verifyCaller("unregisterSplitScreenListener")) {
-                return;
-            }
-            mISplitScreenListener = null;
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mSplitScreenOptional.ifPresent(
-                        s -> s.unregisterSplitScreenListener(mSplitScreenListener));
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void setSideStageVisibility(boolean visible) {
-            if (!verifyCaller("setSideStageVisibility")) {
-                return;
-            }
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mSplitScreenOptional.ifPresent(s -> s.setSideStageVisibility(visible));
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void exitSplitScreen() {
-            if (!verifyCaller("exitSplitScreen")) {
-                return;
-            }
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mSplitScreenOptional.ifPresent(s -> s.exitSplitScreen());
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
-            if (!verifyCaller("exitSplitScreenOnHide")) {
-                return;
-            }
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mSplitScreenOptional.ifPresent(s -> s.exitSplitScreenOnHide(exitSplitScreenOnHide));
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void startTask(int taskId, int stage, int position, Bundle options) {
-            if (!verifyCaller("startTask")) {
-                return;
-            }
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mSplitScreenOptional.ifPresent(
-                        s -> s.startTask(taskId, stage, position, options));
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void startShortcut(String packageName, String shortcutId, int stage, int position,
-                Bundle options, UserHandle user) {
-            if (!verifyCaller("startShortcut")) {
-                return;
-            }
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mSplitScreenOptional.ifPresent(s ->
-                        s.startShortcut(packageName, shortcutId, stage, position, options, user));
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void startIntent(PendingIntent intent, Intent fillInIntent,
-                int stage, int position, Bundle options) {
-            if (!verifyCaller("startIntent")) {
-                return;
-            }
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mSplitScreenOptional.ifPresent(s ->
-                        s.startIntent(intent, mContext, fillInIntent, stage, position, options));
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void removeFromSideStage(int taskId) {
-            if (!verifyCaller("removeFromSideStage")) {
-                return;
-            }
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mSplitScreenOptional.ifPresent(
-                        s -> s.removeFromSideStage(taskId));
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
         private boolean verifyCaller(String reason) {
             final int callerId = Binder.getCallingUserHandle().getIdentifier();
             if (callerId != mCurrentBoundedUserId) {
@@ -757,6 +495,22 @@
             params.putBinder(KEY_EXTRA_SYSUI_PROXY, mSysUiProxy.asBinder());
             params.putFloat(KEY_EXTRA_WINDOW_CORNER_RADIUS, mWindowCornerRadius);
             params.putBoolean(KEY_EXTRA_SUPPORTS_WINDOW_CORNERS, mSupportsRoundedCornersOnWindows);
+
+            mPipOptional.ifPresent((pip) -> params.putBinder(
+                    KEY_EXTRA_SHELL_PIP,
+                    pip.createExternalInterface().asBinder()));
+            mSplitScreenOptional.ifPresent((splitscreen) -> params.putBinder(
+                    KEY_EXTRA_SHELL_SPLIT_SCREEN,
+                    splitscreen.createExternalInterface().asBinder()));
+            mOneHandedOptional.ifPresent((onehanded) -> params.putBinder(
+                    KEY_EXTRA_SHELL_ONE_HANDED,
+                    onehanded.createExternalInterface().asBinder()));
+            params.putBinder(KEY_EXTRA_SHELL_SHELL_TRANSITIONS,
+                    mShellTransitions.createExternalInterface().asBinder());
+            mStartingSurface.ifPresent((startingwindow) -> params.putBinder(
+                    KEY_EXTRA_SHELL_STARTING_WINDOW,
+                    startingwindow.createExternalInterface().asBinder()));
+
             try {
                 mOverviewProxy.onInitialize(params);
             } catch (RemoteException e) {
@@ -796,42 +550,11 @@
     private final StatusBarWindowCallback mStatusBarWindowCallback = this::onStatusBarStateChanged;
     private final BiConsumer<Rect, Rect> mSplitScreenBoundsChangeListener =
             this::notifySplitScreenBoundsChanged;
-    private final Consumer<Boolean> mPinnedStackAnimationCallback =
-            this::notifyPinnedStackAnimationStarted;
-
-    private final BiConsumer<Integer, Integer> mStartingWindowListener =
-            this::notifyTaskLaunching;
 
     // This is the death handler for the binder from the launcher service
     private final IBinder.DeathRecipient mOverviewServiceDeathRcpt
             = this::cleanupAfterDeath;
 
-    private ISplitScreenListener mISplitScreenListener;
-    private final SplitScreen.SplitScreenListener mSplitScreenListener =
-            new SplitScreen.SplitScreenListener() {
-        @Override
-        public void onStagePositionChanged(int stage, int position) {
-            try {
-                if (mISplitScreenListener != null) {
-                    mISplitScreenListener.onStagePositionChanged(stage, position);
-                }
-            } catch (RemoteException e) {
-                Log.e(TAG_OPS, "onStagePositionChanged", e);
-            }
-        }
-
-        @Override
-        public void onTaskStageChanged(int taskId, int stage, boolean visible) {
-            try {
-                if (mISplitScreenListener != null) {
-                    mISplitScreenListener.onTaskStageChanged(taskId, stage, visible);
-                }
-            } catch (RemoteException e) {
-                Log.e(TAG_OPS, "onTaskStageChanged", e);
-            }
-        }
-    };
-
     @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
     @Inject
     public OverviewProxyService(Context context, CommandQueue commandQueue,
@@ -844,7 +567,7 @@
             Optional<Lazy<StatusBar>> statusBarOptionalLazy,
             Optional<OneHanded> oneHandedOptional,
             BroadcastDispatcher broadcastDispatcher,
-            RemoteTransitions shellTransitions,
+            ShellTransitions shellTransitions,
             Optional<StartingSurface> startingSurface) {
         super(broadcastDispatcher);
         mContext = context;
@@ -961,29 +684,6 @@
         }
     }
 
-    private void notifyPinnedStackAnimationStarted(Boolean isAnimationStarted) {
-        if (mIPinnedStackAnimationListener == null) {
-            return;
-        }
-        try {
-            mIPinnedStackAnimationListener.onPinnedStackAnimationStarted();
-        } catch (RemoteException e) {
-            Log.e(TAG_OPS, "Failed to call onPinnedStackAnimationStarted()", e);
-        }
-    }
-
-    private void notifyTaskLaunching(int taskId, int supportedType) {
-        if (mIStartingWindowListener == null) {
-            return;
-        }
-
-        try {
-            mIStartingWindowListener.onTaskLaunching(taskId, supportedType);
-        } catch (RemoteException e) {
-            Log.e(TAG_OPS, "Failed to call notifyTaskLaunching()", e);
-        }
-    }
-
     private void onStatusBarStateChanged(boolean keyguardShowing, boolean keyguardOccluded,
             boolean bouncerShowing) {
         mSysUiState.setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING,
@@ -1027,12 +727,6 @@
         // Clean up the minimized state if launcher dies
         mLegacySplitScreenOptional.ifPresent(
                 splitScreen -> splitScreen.setMinimized(false));
-
-        // Clean up any registered remote transitions
-        for (int i = mRemoteTransitions.size() - 1; i >= 0; --i) {
-            mShellTransitions.unregisterRemote(mRemoteTransitions.valueAt(i));
-        }
-        mRemoteTransitions.clear();
     }
 
     public void startConnectionToCurrentUser() {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java b/packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java
index 07adc7b..730702e 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java
@@ -34,6 +34,8 @@
 import java.util.Iterator;
 import java.util.List;
 
+import javax.inject.Inject;
+
 /**
  * Owns a series of partial screen captures (tiles).
  * <p>
@@ -47,6 +49,7 @@
     private CallbackRegistry<OnBoundsChangedListener, ImageTileSet, Rect> mOnBoundsListeners;
     private CallbackRegistry<OnContentChangedListener, ImageTileSet, Rect> mContentListeners;
 
+    @Inject
     ImageTileSet(@UiThread Handler handler) {
         mHandler = handler;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
index 3ac884b..6a004c2 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
@@ -29,11 +29,9 @@
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
-import android.os.RemoteException;
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.Log;
-import android.view.IScrollCaptureConnection;
 import android.view.IWindowManager;
 import android.view.ScrollCaptureResponse;
 import android.view.View;
@@ -78,7 +76,6 @@
 
     private ImageView mPreview;
     private View mSave;
-    private View mCancel;
     private View mEdit;
     private View mShare;
     private CropView mCropView;
@@ -101,12 +98,12 @@
     @Inject
     public LongScreenshotActivity(UiEventLogger uiEventLogger, ImageExporter imageExporter,
             @Main Executor mainExecutor, @Background Executor bgExecutor, IWindowManager wms,
-            Context context) {
+            Context context, ScrollCaptureController scrollCaptureController) {
         mUiEventLogger = uiEventLogger;
         mUiExecutor = mainExecutor;
         mBackgroundExecutor = bgExecutor;
         mImageExporter = imageExporter;
-        mScrollCaptureController = new ScrollCaptureController(context, bgExecutor, wms);
+        mScrollCaptureController = scrollCaptureController;
     }
 
 
@@ -119,7 +116,6 @@
 
         mPreview = requireViewById(R.id.preview);
         mSave = requireViewById(R.id.save);
-        mCancel = requireViewById(R.id.cancel);
         mEdit = requireViewById(R.id.edit);
         mShare = requireViewById(R.id.share);
         mCropView = requireViewById(R.id.crop_view);
@@ -127,7 +123,6 @@
         mCropView.setCropInteractionListener(mMagnifierView);
 
         mSave.setOnClickListener(this::onClicked);
-        mCancel.setOnClickListener(this::onClicked);
         mEdit.setOnClickListener(this::onClicked);
         mShare.setOnClickListener(this::onClicked);
 
@@ -315,7 +310,6 @@
 
     private void setButtonsEnabled(boolean enabled) {
         mSave.setEnabled(enabled);
-        mCancel.setEnabled(enabled);
         mEdit.setEnabled(enabled);
         mShare.setEnabled(enabled);
     }
@@ -352,8 +346,6 @@
         setButtonsEnabled(false);
         if (id == R.id.save) {
             startExport(PendingAction.SAVE);
-        } else if (id == R.id.cancel) {
-            finishAndRemoveTask();
         } else if (id == R.id.edit) {
             mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_EDIT);
             startExport(PendingAction.EDIT);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 798a063..c1ae292 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -25,6 +25,7 @@
 import static com.android.systemui.screenshot.LogConfig.DEBUG_CALLBACK;
 import static com.android.systemui.screenshot.LogConfig.DEBUG_DISMISS;
 import static com.android.systemui.screenshot.LogConfig.DEBUG_INPUT;
+import static com.android.systemui.screenshot.LogConfig.DEBUG_SCROLL;
 import static com.android.systemui.screenshot.LogConfig.DEBUG_UI;
 import static com.android.systemui.screenshot.LogConfig.DEBUG_WINDOW;
 import static com.android.systemui.screenshot.LogConfig.logTag;
@@ -90,6 +91,7 @@
 import com.google.common.util.concurrent.ListenableFuture;
 
 import java.util.List;
+import java.util.concurrent.CancellationException;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
@@ -570,6 +572,15 @@
                 mLastScrollCaptureResponse.close();
             }
             mLastScrollCaptureResponse = responseFuture.get();
+            if (!mLastScrollCaptureResponse.isConnected()) {
+                // No connection means that the target window wasn't found
+                // or that it cannot support scroll capture.
+                Log.d(TAG, "ScrollCapture: " + mLastScrollCaptureResponse.getDescription() + " ["
+                 + mLastScrollCaptureResponse.getWindowTitle() + "]");
+                return;
+            }
+            Log.d(TAG, "ScrollCapture: connected to window ["
+                    + mLastScrollCaptureResponse.getWindowTitle() + "]");
             final Intent intent = new Intent(mContext, LongScreenshotActivity.class);
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
             intent.putExtra(LongScreenshotActivity.EXTRA_CAPTURE_RESPONSE,
@@ -580,6 +591,8 @@
                 mContext.startActivity(intent);
                 dismissScreenshot(false);
             });
+        } catch (CancellationException e) {
+            // Ignore
         } catch (InterruptedException | ExecutionException e) {
             Log.e(TAG, "requestScrollCapture failed", e);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
index 4f69904..d3dd048 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
@@ -18,19 +18,16 @@
 
 import android.content.Context;
 import android.graphics.Bitmap;
-import android.graphics.HardwareRenderer;
-import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
-import android.graphics.RenderNode;
 import android.graphics.drawable.Drawable;
 import android.provider.Settings;
 import android.util.Log;
-import android.view.IWindowManager;
 import android.view.ScrollCaptureResponse;
 
 import androidx.concurrent.futures.CallbackToFutureAdapter;
 import androidx.concurrent.futures.CallbackToFutureAdapter.Completer;
 
+import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.screenshot.ScrollCaptureClient.CaptureResult;
 import com.android.systemui.screenshot.ScrollCaptureClient.Session;
 
@@ -39,6 +36,8 @@
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
 
+import javax.inject.Inject;
+
 /**
  * Interaction controller between the UI and ScrollCaptureClient.
  */
@@ -131,11 +130,13 @@
         }
     }
 
-    ScrollCaptureController(Context context, Executor bgExecutor, IWindowManager wms) {
+    @Inject
+    ScrollCaptureController(Context context, @Background Executor bgExecutor,
+            ScrollCaptureClient client, ImageTileSet imageTileSet) {
         mContext = context;
         mBgExecutor = bgExecutor;
-        mImageTileSet = new ImageTileSet(context.getMainThreadHandler());
-        mClient = new ScrollCaptureClient(mContext, wms);
+        mClient = client;
+        mImageTileSet = imageTileSet;
     }
 
     /**
@@ -252,8 +253,10 @@
             return;
         }
 
-        int nextTop = (mScrollingUp)
-                ? result.captured.top - mSession.getTileHeight() : result.captured.bottom;
+        // Partial or empty results caused the direction the flip, so we can reliably use the
+        // requested edges to determine the next top.
+        int nextTop = (mScrollingUp) ? result.requested.top - mSession.getTileHeight()
+                : result.requested.bottom;
         requestNextTile(nextTop);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 0599039..1ff30a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -37,6 +37,7 @@
 import android.hardware.biometrics.IBiometricSysuiReceiver;
 import android.hardware.biometrics.PromptInfo;
 import android.hardware.display.DisplayManager;
+import android.hardware.fingerprint.IUdfpsHbmListener;
 import android.inputmethodservice.InputMethodService.BackDispositionMode;
 import android.os.Bundle;
 import android.os.Handler;
@@ -142,6 +143,7 @@
     //TODO(b/169175022) Update name and when feature name is locked.
     private static final int MSG_EMERGENCY_ACTION_LAUNCH_GESTURE      = 58 << MSG_SHIFT;
     private static final int MSG_SET_NAVIGATION_BAR_LUMA_SAMPLING_ENABLED = 59 << MSG_SHIFT;
+    private static final int MSG_SET_UDFPS_HBM_LISTENER = 60 << MSG_SHIFT;
 
     public static final int FLAG_EXCLUDE_NONE = 0;
     public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -286,21 +288,38 @@
                 IBiometricSysuiReceiver receiver,
                 int[] sensorIds, boolean credentialAllowed,
                 boolean requireConfirmation, int userId, String opPackageName,
-                long operationId) { }
-        default void onBiometricAuthenticated() { }
-        default void onBiometricHelp(String message) { }
-        default void onBiometricError(int modality, int error, int vendorCode) { }
-        default void hideAuthenticationDialog() { }
+                long operationId) {
+        }
+
+        default void onBiometricAuthenticated() {
+        }
+
+        default void onBiometricHelp(String message) {
+        }
+
+        default void onBiometricError(int modality, int error, int vendorCode) {
+        }
+
+        default void hideAuthenticationDialog() {
+        }
+
+        /**
+         * @see IStatusBar#setUdfpsHbmListener(IUdfpsHbmListener)
+         */
+        default void setUdfpsHbmListener(IUdfpsHbmListener listener) {
+        }
 
         /**
          * @see IStatusBar#onDisplayReady(int)
          */
-        default void onDisplayReady(int displayId) { }
+        default void onDisplayReady(int displayId) {
+        }
 
         /**
          * @see DisplayManager.DisplayListener#onDisplayRemoved(int)
          */
-        default void onDisplayRemoved(int displayId) { }
+        default void onDisplayRemoved(int displayId) {
+        }
 
         /**
          * @see IStatusBar#onRecentsAnimationStateChanged(boolean)
@@ -893,6 +912,13 @@
     }
 
     @Override
+    public void setUdfpsHbmListener(IUdfpsHbmListener listener) {
+        synchronized (mLock) {
+            mHandler.obtainMessage(MSG_SET_UDFPS_HBM_LISTENER, listener).sendToTarget();
+        }
+    }
+
+    @Override
     public void onDisplayReady(int displayId) {
         synchronized (mLock) {
             mHandler.obtainMessage(MSG_DISPLAY_READY, displayId, 0).sendToTarget();
@@ -1286,7 +1312,7 @@
                         mCallbacks.get(i).onBiometricHelp((String) msg.obj);
                     }
                     break;
-                case MSG_BIOMETRIC_ERROR:
+                case MSG_BIOMETRIC_ERROR: {
                     SomeArgs someArgs = (SomeArgs) msg.obj;
                     for (int i = 0; i < mCallbacks.size(); i++) {
                         mCallbacks.get(i).onBiometricError(
@@ -1297,11 +1323,17 @@
                     }
                     someArgs.recycle();
                     break;
+                }
                 case MSG_BIOMETRIC_HIDE:
                     for (int i = 0; i < mCallbacks.size(); i++) {
                         mCallbacks.get(i).hideAuthenticationDialog();
                     }
                     break;
+                case MSG_SET_UDFPS_HBM_LISTENER:
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).setUdfpsHbmListener((IUdfpsHbmListener) msg.obj);
+                    }
+                    break;
                 case MSG_SHOW_CHARGING_ANIMATION:
                     for (int i = 0; i < mCallbacks.size(); i++) {
                         mCallbacks.get(i).showWirelessChargingAnimation(msg.arg1);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
index c8e0d60..708bdfe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
@@ -83,6 +83,10 @@
         return mFlagReader.isEnabled(R.bool.flag_monet);
     }
 
+    public boolean isQuickAccessWalletEnabled() {
+        return mFlagReader.isEnabled(R.bool.flag_wallet);
+    }
+
     public boolean isNavigationBarOverlayEnabled() {
         return mFlagReader.isEnabled(R.bool.flag_navigation_bar_overlay);
     }
@@ -94,4 +98,8 @@
     public boolean isAlarmTileAvailable() {
         return mFlagReader.isEnabled(R.bool.flag_alarm_tile);
     }
+
+    public boolean isChargingRippleEnabled() {
+        return mFlagReader.isEnabled(R.bool.flag_charging_ripple);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
index c1feaca..563470d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
@@ -82,6 +82,31 @@
     }
 }
 
+class CircleReveal(
+    /** X-value of the circle center of the reveal. */
+    val centerX: Float,
+    /** Y-value of the circle center of the reveal. */
+    val centerY: Float,
+    /** Radius of initial state of circle reveal */
+    val startRadius: Float,
+    /** Radius of end state of circle reveal */
+    val endRadius: Float
+) : LightRevealEffect {
+    override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) {
+        val interpolatedAmount = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(amount)
+        val fadeAmount =
+            LightRevealEffect.getPercentPastThreshold(interpolatedAmount, 0.75f)
+        val radius = startRadius + ((endRadius - startRadius) * interpolatedAmount)
+        scrim.revealGradientEndColorAlpha = 1f - fadeAmount
+        scrim.setRevealGradientBounds(
+            centerX - radius /* left */,
+            centerY - radius /* top */,
+            centerX + radius /* right */,
+            centerY + radius /* bottom */
+        )
+    }
+}
+
 class PowerButtonReveal(
     /** Approximate Y-value of the center of the power button on the physical device. */
     val powerButtonY: Float
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index e119907..3daa2b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -132,6 +132,7 @@
         mHiddenShelfIconSize = res.getDimensionPixelOffset(R.dimen.hidden_shelf_icon_size);
         mGapHeight = res.getDimensionPixelSize(R.dimen.qs_notification_padding);
 
+        mShelfIcons.setInNotificationIconShelf(true);
         if (!mShowNotificationShelf) {
             setVisibility(GONE);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/charging/ChargingRippleView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/charging/ChargingRippleView.kt
new file mode 100644
index 0000000..6f80317
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/charging/ChargingRippleView.kt
@@ -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 com.android.systemui.statusbar.charging
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ValueAnimator
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.graphics.PointF
+import android.util.AttributeSet
+import android.view.View
+import kotlin.math.max
+
+private const val RIPPLE_ANIMATION_DURATION: Long = 1500
+private const val RIPPLE_SPARKLE_STRENGTH: Float = 0.3f
+
+/**
+ * Expanding ripple effect that shows when charging begins.
+ */
+class ChargingRippleView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
+    private var rippleInProgress: Boolean = false
+    private val rippleShader = RippleShader()
+    private val defaultColor: Int = 0xffffffff.toInt()
+    private val ripplePaint = Paint()
+
+    init {
+        rippleShader.color = defaultColor
+        rippleShader.progress = 0f
+        rippleShader.sparkleStrength = RIPPLE_SPARKLE_STRENGTH
+        ripplePaint.shader = rippleShader
+    }
+
+    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
+        rippleShader.origin = PointF(measuredWidth / 2f, measuredHeight.toFloat())
+        rippleShader.radius = max(measuredWidth, measuredHeight).toFloat()
+        super.onLayout(changed, left, top, right, bottom)
+    }
+
+    fun startRipple() {
+        if (rippleInProgress) {
+            return // Ignore if ripple effect is already playing
+        }
+        val animator = ValueAnimator.ofFloat(0f, 1f)
+        animator.duration = RIPPLE_ANIMATION_DURATION
+        animator.addUpdateListener { animator ->
+            val now = animator.currentPlayTime
+            val phase = now / 30000f
+            rippleShader.progress = animator.animatedValue as Float
+            rippleShader.noisePhase = phase
+            invalidate()
+        }
+        animator.addListener(object : AnimatorListenerAdapter() {
+            override fun onAnimationEnd(animation: Animator?) {
+                rippleInProgress = false
+                visibility = View.GONE
+            }
+        })
+        animator.start()
+        visibility = View.VISIBLE
+        rippleInProgress = true
+    }
+
+    fun setColor(color: Int) {
+        rippleShader.color = color
+    }
+
+    override fun onDraw(canvas: Canvas?) {
+        canvas?.drawRect(0f, 0f, width.toFloat(), height.toFloat(), ripplePaint)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/charging/RippleShader.kt b/packages/SystemUI/src/com/android/systemui/statusbar/charging/RippleShader.kt
new file mode 100644
index 0000000..5547c1e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/charging/RippleShader.kt
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.charging
+
+import android.graphics.Color
+import android.graphics.PointF
+import android.graphics.RuntimeShader
+
+/**
+ * Shader class that renders an expanding charging ripple effect. A charging ripple contains
+ * three elements:
+ * 1. an expanding filled circle that appears in the beginning and quickly fades away
+ * 2. an expanding ring that appears throughout the effect
+ * 3. an expanding ring-shaped area that reveals noise over #2.
+ *
+ * Modeled after frameworks/base/graphics/java/android/graphics/drawable/RippleShader.java.
+ */
+class RippleShader internal constructor() : RuntimeShader(SHADER, false) {
+    companion object {
+        private const val SHADER_UNIFORMS = """uniform vec2 in_origin;
+                uniform float in_progress;
+                uniform float in_maxRadius;
+                uniform float in_noisePhase;
+                uniform vec4 in_color;
+                uniform float in_sparkle_strength;"""
+        private const val SHADER_LIB = """float triangleNoise(vec2 n) {
+                    n  = fract(n * vec2(5.3987, 5.4421));
+                    n += dot(n.yx, n.xy + vec2(21.5351, 14.3137));
+                    float xy = n.x * n.y;
+                    return fract(xy * 95.4307) + fract(xy * 75.04961) - 1.0;
+                }
+                const float PI = 3.1415926535897932384626;
+
+                float threshold(float v, float l, float h) {
+                  return step(l, v) * (1.0 - step(h, v));
+                }
+
+                float sparkles(vec2 uv, float t) {
+                  float n = triangleNoise(uv);
+                  float s = 0.0;
+                  for (float i = 0; i < 4; i += 1) {
+                    float l = i * 0.25;
+                    float h = l + 0.025;
+                    float o = abs(sin(0.1 * PI * (t + i)));
+                    s += threshold(n + o, l, h);
+                  }
+                  return saturate(s);
+                }
+
+                float softCircle(vec2 uv, vec2 xy, float radius, float blur) {
+                  float blurHalf = blur * 0.5;
+                  float d = distance(uv, xy);
+                  return 1. - smoothstep(1. - blurHalf, 1. + blurHalf, d / radius);
+                }
+
+                float softRing(vec2 uv, vec2 xy, float radius, float blur) {
+                  float thickness = 0.4;
+                  float circle_outer = softCircle(uv, xy,
+                      radius + thickness * radius * 0.5, blur);
+                  float circle_inner = softCircle(uv, xy,
+                      radius - thickness * radius * 0.5, blur);
+                  return circle_outer - circle_inner;
+                }
+
+                float subProgress(float start, float end, float progress) {
+                    float sub = clamp(progress, start, end);
+                    return (sub - start) / (end - start);
+                }
+
+                float smoothstop2(float t) {
+                  return 1 - (1 - t) * (1 - t);
+                }"""
+        private const val SHADER_MAIN = """vec4 main(vec2 p) {
+                    float fadeIn = subProgress(0., 0.1, in_progress);
+                    float fadeOutNoise = subProgress(0.8, 1., in_progress);
+                    float fadeOutRipple = subProgress(0.7, 1., in_progress);
+                    float fadeCircle = subProgress(0., 0.5, in_progress);
+                    float radius = smoothstop2(in_progress) * in_maxRadius;
+                    float sparkleRing = softRing(p, in_origin, radius, 0.5);
+                    float sparkleAlpha = min(fadeIn, 1. - fadeOutNoise);
+                    float sparkle = sparkles(p, in_noisePhase) * sparkleRing * sparkleAlpha;
+                    float circle = softCircle(p, in_origin, radius * 1.2, 0.5)
+                        * (1 - fadeCircle);
+                    float fadeRipple = min(fadeIn, 1.-fadeOutRipple);
+                    float rippleAlpha = softRing(p, in_origin, radius, 0.5)
+                        * fadeRipple * in_color.a;
+                    vec4 ripple = in_color * max(circle, rippleAlpha) * 0.4;
+                    return mix(ripple, vec4(sparkle), sparkle * in_sparkle_strength);
+                }"""
+        private const val SHADER = SHADER_UNIFORMS + SHADER_LIB + SHADER_MAIN
+    }
+
+    /**
+     * Maximum radius of the ripple.
+     */
+    var radius: Float = 0.0f
+        set(value) { setUniform("in_maxRadius", value) }
+
+    /**
+     * Origin coordinate of the ripple.
+     */
+    var origin: PointF = PointF()
+        set(value) { setUniform("in_origin", floatArrayOf(value.x, value.y)) }
+
+    /**
+     * Progress of the ripple. Float value between [0, 1].
+     */
+    var progress: Float = 0.0f
+        set(value) { setUniform("in_progress", value) }
+
+    /**
+     * Continuous offset used as noise phase.
+     */
+    var noisePhase: Float = 0.0f
+        set(value) { setUniform("in_noisePhase", value) }
+
+    /**
+     * A hex value representing the ripple color, in the format of ARGB
+     */
+    var color: Int = 0xffffff.toInt()
+        set(value) {
+            val color = Color.valueOf(value)
+            setUniform("in_color", floatArrayOf(color.red(),
+                    color.green(), color.blue(), color.alpha()))
+        }
+
+    /**
+     * Noise sparkle intensity. Expected value between [0, 1]. The sparkle is white, and thus
+     * with strength 0 it's transparent, leaving the ripple fully smooth, while with strength 1
+     * it's opaque white and looks the most grainy.
+     */
+    var sparkleStrength: Float = 0.0f
+        set(value) { setUniform("in_sparkle_strength", value) }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
new file mode 100644
index 0000000..b567ad4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.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 com.android.systemui.statusbar.charging
+
+import android.content.Context
+import android.content.res.Configuration
+import android.util.DisplayMetrics
+import android.view.View
+import android.view.ViewGroupOverlay
+import com.android.internal.annotations.VisibleForTesting
+import com.android.settingslib.Utils
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.statusbar.commandline.Command
+import com.android.systemui.statusbar.commandline.CommandRegistry
+import com.android.systemui.statusbar.policy.BatteryController
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import java.io.PrintWriter
+import javax.inject.Inject
+
+/***
+ * Controls the ripple effect that shows when wired charging begins.
+ * The ripple uses the accent color of the current theme.
+ */
+@SysUISingleton
+class WiredChargingRippleController @Inject constructor(
+    commandRegistry: CommandRegistry,
+    batteryController: BatteryController,
+    configurationController: ConfigurationController,
+    featureFlags: FeatureFlags,
+    private val context: Context,
+    private val keyguardStateController: KeyguardStateController
+) {
+    private var pluggedIn: Boolean? = null
+    private val rippleEnabled: Boolean = featureFlags.isChargingRippleEnabled
+    @VisibleForTesting
+    var rippleView: ChargingRippleView = ChargingRippleView(context, attrs = null)
+
+    init {
+        val batteryStateChangeCallback = object : BatteryController.BatteryStateChangeCallback {
+            override fun onBatteryLevelChanged(
+                level: Int,
+                nowPluggedIn: Boolean,
+                charging: Boolean
+            ) {
+                if (!rippleEnabled) {
+                    return
+                }
+                val wasPluggedIn = pluggedIn
+                pluggedIn = nowPluggedIn
+                // Only triggers when the keyguard is active and the device is just plugged in.
+                if (wasPluggedIn == false && nowPluggedIn && keyguardStateController.isShowing) {
+                    rippleView.startRipple()
+                }
+            }
+        }
+        batteryController.addCallback(batteryStateChangeCallback)
+
+        val configurationChangedListener = object : ConfigurationController.ConfigurationListener {
+            override fun onUiModeChanged() {
+                updateRippleColor()
+            }
+            override fun onThemeChanged() {
+                updateRippleColor()
+            }
+            override fun onOverlayChanged() {
+                updateRippleColor()
+            }
+            override fun onConfigChanged(newConfig: Configuration?) {
+                layoutRippleView()
+            }
+        }
+        configurationController.addCallback(configurationChangedListener)
+
+        commandRegistry.registerCommand("charging-ripple") { ChargingRippleCommand() }
+    }
+
+    fun setViewHost(viewHost: View) {
+        // Add the ripple view as an overlay of the root view so that it always
+        // shows on top.
+        viewHost.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
+            override fun onViewDetachedFromWindow(view: View?) {}
+
+            override fun onViewAttachedToWindow(view: View?) {
+                (viewHost.viewRootImpl.view.overlay as ViewGroupOverlay).add(rippleView)
+                layoutRippleView()
+                viewHost.removeOnAttachStateChangeListener(this)
+            }
+        })
+
+        updateRippleColor()
+    }
+
+    private fun layoutRippleView() {
+        // Overlays are not auto measured and laid out so we do it manually here.
+        val displayMetrics = DisplayMetrics()
+        context.display.getRealMetrics(displayMetrics)
+        val width = displayMetrics.widthPixels
+        val height = displayMetrics.heightPixels
+        if (width != rippleView.width || height != rippleView.height) {
+            rippleView.measure(
+                    View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
+                    View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY))
+            rippleView.layout(0, 0, width, height)
+        }
+    }
+
+    private fun updateRippleColor() {
+        rippleView.setColor(
+                Utils.getColorAttr(context, android.R.attr.colorAccent).defaultColor)
+    }
+
+    inner class ChargingRippleCommand : Command {
+        override fun execute(pw: PrintWriter, args: List<String>) {
+            rippleView.startRipple()
+        }
+
+        override fun help(pw: PrintWriter) {
+            pw.println("Usage: adb shell cmd statusbar charging-ripple")
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/commandline/CommandRegistry.kt b/packages/SystemUI/src/com/android/systemui/statusbar/commandline/CommandRegistry.kt
index ce0a08c..1da42a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/commandline/CommandRegistry.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/commandline/CommandRegistry.kt
@@ -192,9 +192,9 @@
         val pref = args[0]
 
         when (pref) {
-            Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING -> {
+            Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING_IN_S -> {
                 val value = Integer.parseInt(args[1])
-                Prefs.putBoolean(context, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING, value != 0)
+                Prefs.putBoolean(context, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING_IN_S, value != 0)
             }
             else -> {
                 pw.println("Cannot set pref ($pref)")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index 0957f78..617dadb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -31,6 +31,7 @@
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dagger.qualifiers.UiBackground;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.settings.UserContextProvider;
 import com.android.systemui.statusbar.FeatureFlags;
@@ -71,6 +72,7 @@
 import com.android.systemui.statusbar.notification.row.PriorityOnboardingDialogController;
 import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager;
 import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm;
+import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.util.leak.LeakDetector;
@@ -133,6 +135,8 @@
             AccessibilityManager accessibilityManager,
             HighPriorityProvider highPriorityProvider,
             INotificationManager notificationManager,
+            NotificationEntryManager notificationEntryManager,
+            PeopleSpaceWidgetManager peopleSpaceWidgetManager,
             LauncherApps launcherApps,
             ShortcutManager shortcutManager,
             ChannelEditorDialogController channelEditorDialogController,
@@ -141,7 +145,8 @@
             AssistantFeedbackController assistantFeedbackController,
             Optional<BubblesManager> bubblesManagerOptional,
             UiEventLogger uiEventLogger,
-            OnUserInteractionCallback onUserInteractionCallback) {
+            OnUserInteractionCallback onUserInteractionCallback,
+            ShadeController shadeController) {
         return new NotificationGutsManager(
                 context,
                 statusBarLazy,
@@ -150,6 +155,8 @@
                 accessibilityManager,
                 highPriorityProvider,
                 notificationManager,
+                notificationEntryManager,
+                peopleSpaceWidgetManager,
                 launcherApps,
                 shortcutManager,
                 channelEditorDialogController,
@@ -158,7 +165,8 @@
                 assistantFeedbackController,
                 bubblesManagerOptional,
                 uiEventLogger,
-                onUserInteractionCallback);
+                onUserInteractionCallback,
+                shadeController);
     }
 
     /** Provides an instance of {@link VisualStabilityManager} */
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 dff97a6..fd5128a 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
@@ -17,7 +17,6 @@
 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
@@ -132,11 +131,7 @@
             entryManager.attach(notificationListener)
         }
 
-        val showPeopleSpace = Settings.Global.getInt(context.contentResolver,
-                Settings.Global.SHOW_PEOPLE_SPACE, 1)
-        if (showPeopleSpace == 1) {
-            peopleSpaceWidgetManager.attach(notificationListener)
-        }
+        peopleSpaceWidgetManager.attach(notificationListener)
     }
 
     override fun dump(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index adeba90..b4ab8cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -69,9 +69,11 @@
 import com.android.systemui.R;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
 import com.android.systemui.statusbar.notification.NotificationChannelHelper;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
+import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.wmshell.BubblesManager;
 
 import java.lang.annotation.Retention;
@@ -86,15 +88,16 @@
         NotificationGuts.GutsContent {
     private static final String TAG = "ConversationGuts";
 
-
     private INotificationManager mINotificationManager;
     private ShortcutManager mShortcutManager;
     private PackageManager mPm;
+    private PeopleSpaceWidgetManager mPeopleSpaceWidgetManager;
     private ConversationIconFactory mIconFactory;
     private OnUserInteractionCallback mOnUserInteractionCallback;
     private Handler mMainHandler;
     private Handler mBgHandler;
     private Optional<BubblesManager> mBubblesManagerOptional;
+    private ShadeController mShadeController;
     private String mPackageName;
     private String mAppName;
     private int mAppUid;
@@ -169,9 +172,16 @@
 
     private OnClickListener mOnDone = v -> {
         mPressedApply = true;
-        // If the user selected Priority, maybe show the priority onboarding
+
+        // If the user selected Priority, maybe show the priority onboarding.
+        // If the user selected Priority and the previous selection was not priority, show a
+        // People Tile add request. If showing the priority onboarding, however, delay the request
+        // to when the onboarding dialog closes.
         if (mSelectedAction == ACTION_FAVORITE && shouldShowPriorityOnboarding()) {
             showPriorityOnboarding();
+        } else if (mSelectedAction == ACTION_FAVORITE && getPriority() != mSelectedAction) {
+            mShadeController.animateCollapsePanels();
+            mPeopleSpaceWidgetManager.requestPinAppWidget(mShortcutInfo);
         }
         mGutsContainer.closeControls(v, true);
     };
@@ -209,6 +219,7 @@
             @Action int selectedAction,
             ShortcutManager shortcutManager,
             PackageManager pm,
+            PeopleSpaceWidgetManager peopleSpaceWidgetManager,
             INotificationManager iNotificationManager,
             OnUserInteractionCallback onUserInteractionCallback,
             String pkg,
@@ -224,10 +235,12 @@
             @Main Handler mainHandler,
             @Background Handler bgHandler,
             OnConversationSettingsClickListener onConversationSettingsClickListener,
-            Optional<BubblesManager> bubblesManagerOptional) {
+            Optional<BubblesManager> bubblesManagerOptional,
+            ShadeController shadeController) {
         mPressedApply = false;
         mSelectedAction = selectedAction;
         mINotificationManager = iNotificationManager;
+        mPeopleSpaceWidgetManager = peopleSpaceWidgetManager;
         mOnUserInteractionCallback = onUserInteractionCallback;
         mPackageName = pkg;
         mEntry = entry;
@@ -245,6 +258,7 @@
         mUserContext = userContext;
         mBubbleMetadata = bubbleMetadata;
         mBubblesManagerOptional = bubblesManagerOptional;
+        mShadeController = shadeController;
         mBuilderProvider = builderProvider;
         mMainHandler = mainHandler;
         mBgHandler = bgHandler;
@@ -527,7 +541,7 @@
     }
 
     private boolean shouldShowPriorityOnboarding() {
-        return !Prefs.getBoolean(mUserContext, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING, false);
+        return !Prefs.getBoolean(mUserContext, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING_IN_S, false);
     }
 
     private void showPriorityOnboarding() {
@@ -566,9 +580,11 @@
                 .setBadge(mIconFactory.getAppBadge(
                         mPackageName, UserHandle.getUserId(mSbn.getUid())))
                 .setOnSettingsClick(mOnConversationSettingsClickListener)
+                .setPeopleSpaceWidgetManager(mPeopleSpaceWidgetManager)
+                .setShadeController(mShadeController)
                 .build();
 
-        controller.init();
+        controller.init(mShortcutInfo);
         controller.show();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index 6a873b6..1a7f5b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -21,6 +21,7 @@
 
 import android.app.INotificationManager;
 import android.app.NotificationChannel;
+import android.appwidget.AppWidgetManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.LauncherApps;
@@ -49,6 +50,7 @@
 import com.android.systemui.R;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.settings.UserContextProvider;
@@ -59,11 +61,13 @@
 import com.android.systemui.statusbar.StatusBarStateControllerImpl;
 import com.android.systemui.statusbar.notification.AssistantFeedbackController;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
 import com.android.systemui.statusbar.notification.dagger.NotificationsModule;
 import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.wmshell.BubblesManager;
@@ -120,11 +124,15 @@
     private final Optional<BubblesManager> mBubblesManagerOptional;
     private Runnable mOpenRunnable;
     private final INotificationManager mNotificationManager;
+    private final NotificationEntryManager mNotificationEntryManager;
+    private final PeopleSpaceWidgetManager mPeopleSpaceWidgetManager;
     private final LauncherApps mLauncherApps;
     private final ShortcutManager mShortcutManager;
     private final UserContextProvider mContextTracker;
     private final Provider<PriorityOnboardingDialogController.Builder> mBuilderProvider;
     private final UiEventLogger mUiEventLogger;
+    private final ShadeController mShadeController;
+    private final AppWidgetManager mAppWidgetManager;
 
     /**
      * Injected constructor. See {@link NotificationsModule}.
@@ -136,6 +144,8 @@
             AccessibilityManager accessibilityManager,
             HighPriorityProvider highPriorityProvider,
             INotificationManager notificationManager,
+            NotificationEntryManager notificationEntryManager,
+            PeopleSpaceWidgetManager peopleSpaceWidgetManager,
             LauncherApps launcherApps,
             ShortcutManager shortcutManager,
             ChannelEditorDialogController channelEditorDialogController,
@@ -144,7 +154,8 @@
             AssistantFeedbackController assistantFeedbackController,
             Optional<BubblesManager> bubblesManagerOptional,
             UiEventLogger uiEventLogger,
-            OnUserInteractionCallback onUserInteractionCallback) {
+            OnUserInteractionCallback onUserInteractionCallback,
+            ShadeController shadeController) {
         mContext = context;
         mStatusBarLazy = statusBarLazy;
         mMainHandler = mainHandler;
@@ -152,6 +163,8 @@
         mAccessibilityManager = accessibilityManager;
         mHighPriorityProvider = highPriorityProvider;
         mNotificationManager = notificationManager;
+        mNotificationEntryManager = notificationEntryManager;
+        mPeopleSpaceWidgetManager = peopleSpaceWidgetManager;
         mLauncherApps = launcherApps;
         mShortcutManager = shortcutManager;
         mContextTracker = contextTracker;
@@ -161,6 +174,8 @@
         mBubblesManagerOptional = bubblesManagerOptional;
         mUiEventLogger = uiEventLogger;
         mOnUserInteractionCallback = onUserInteractionCallback;
+        mShadeController = shadeController;
+        mAppWidgetManager = AppWidgetManager.getInstance(context);
     }
 
     public void setUpWithPresenter(NotificationPresenter presenter,
@@ -477,6 +492,7 @@
                 notificationInfoView.getSelectedAction(),
                 mShortcutManager,
                 pmUser,
+                mPeopleSpaceWidgetManager,
                 mNotificationManager,
                 mOnUserInteractionCallback,
                 packageName,
@@ -492,7 +508,8 @@
                 mMainHandler,
                 mBgHandler,
                 onConversationSettingsListener,
-                mBubblesManagerOptional);
+                mBubblesManagerOptional,
+                mShadeController);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt
index fab367d..ae1285d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt
@@ -22,6 +22,7 @@
 import android.animation.ValueAnimator
 import android.app.Dialog
 import android.content.Context
+import android.content.pm.ShortcutInfo
 import android.graphics.Color
 import android.graphics.PixelFormat
 import android.graphics.drawable.ColorDrawable
@@ -31,7 +32,6 @@
 import android.text.style.BulletSpan
 import android.view.Gravity
 import android.view.View
-import android.view.ViewGroup
 import android.view.ViewGroup.LayoutParams.MATCH_PARENT
 import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
 import android.view.Window
@@ -44,31 +44,36 @@
 import com.android.systemui.Interpolators.LINEAR_OUT_SLOW_IN
 import com.android.systemui.Prefs
 import com.android.systemui.R
+import com.android.systemui.people.widget.PeopleSpaceWidgetManager
 import com.android.systemui.statusbar.notification.row.NotificationConversationInfo.OnConversationSettingsClickListener
+import com.android.systemui.statusbar.phone.ShadeController
 import javax.inject.Inject
 
-
 /**
  * Controller to handle presenting the priority conversations onboarding dialog
  */
 class PriorityOnboardingDialogController @Inject constructor(
-        val view: View,
-        val context: Context,
-        private val ignoresDnd: Boolean,
-        private val showsAsBubble: Boolean,
-        val icon : Drawable,
-        private val onConversationSettingsClickListener : OnConversationSettingsClickListener,
-        val badge : Drawable
+    val view: View,
+    val context: Context,
+    private val ignoresDnd: Boolean,
+    private val showsAsBubble: Boolean,
+    val icon: Drawable,
+    private val onConversationSettingsClickListener: OnConversationSettingsClickListener,
+    val badge: Drawable,
+    private val peopleSpaceWidgetManager: PeopleSpaceWidgetManager,
+    private val shadeController: ShadeController
 ) {
 
     private lateinit var dialog: Dialog
+    private lateinit var shortcutInfo: ShortcutInfo
     private val OVERSHOOT: Interpolator = PathInterpolator(0.4f, 0f, 0.2f, 1.4f)
     private val IMPORTANCE_ANIM_DELAY = 150L
     private val IMPORTANCE_ANIM_GROW_DURATION = 250L
     private val IMPORTANCE_ANIM_SHRINK_DURATION = 200L
     private val IMPORTANCE_ANIM_SHRINK_DELAY = 25L
 
-    fun init() {
+    fun init(info: ShortcutInfo) {
+        shortcutInfo = info
         initDialog()
     }
 
@@ -78,13 +83,15 @@
 
     private fun done() {
         // Log that the user has seen the onboarding
-        Prefs.putBoolean(context, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING, true)
+        Prefs.putBoolean(context, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING_IN_S, true)
         dialog.dismiss()
+        shadeController.animateCollapsePanels()
+        peopleSpaceWidgetManager.requestPinAppWidget(shortcutInfo)
     }
 
     private fun settings() {
         // Log that the user has seen the onboarding
-        Prefs.putBoolean(context, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING, true)
+        Prefs.putBoolean(context, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING_IN_S, true)
         dialog.dismiss()
         onConversationSettingsClickListener?.onClick()
     }
@@ -95,9 +102,11 @@
         private var ignoresDnd = false
         private var showAsBubble = false
         private lateinit var icon: Drawable
-        private lateinit var onConversationSettingsClickListener
-                : OnConversationSettingsClickListener
-        private lateinit var badge : Drawable
+        private lateinit var onConversationSettingsClickListener:
+                OnConversationSettingsClickListener
+        private lateinit var badge: Drawable
+        private lateinit var peopleSpaceWidgetManager: PeopleSpaceWidgetManager
+        private lateinit var shadeController: ShadeController
 
         fun setView(v: View): Builder {
             view = v
@@ -119,24 +128,36 @@
             return this
         }
 
-        fun setIcon(draw : Drawable) : Builder {
+        fun setIcon(draw: Drawable): Builder {
             icon = draw
             return this
         }
-        fun setBadge(badge : Drawable) : Builder {
+        fun setBadge(badge: Drawable): Builder {
             this.badge = badge
             return this
         }
 
-        fun setOnSettingsClick(onClick : OnConversationSettingsClickListener) : Builder {
+        fun setOnSettingsClick(onClick: OnConversationSettingsClickListener): Builder {
             onConversationSettingsClickListener = onClick
             return this
         }
 
+        fun setShadeController(shadeController: ShadeController): Builder {
+            this.shadeController = shadeController
+            return this
+        }
+
+        fun setPeopleSpaceWidgetManager(peopleSpaceWidgetManager: PeopleSpaceWidgetManager):
+                Builder {
+            this.peopleSpaceWidgetManager = peopleSpaceWidgetManager
+            return this
+        }
+
         fun build(): PriorityOnboardingDialogController {
             val controller = PriorityOnboardingDialogController(
                     view, context, ignoresDnd, showAsBubble, icon,
-                    onConversationSettingsClickListener, badge)
+                    onConversationSettingsClickListener, badge, peopleSpaceWidgetManager,
+                    shadeController)
             return controller
         }
     }
@@ -185,8 +206,8 @@
             val bgSize = context.resources.getDimensionPixelSize(
                     com.android.internal.R.dimen.conversation_icon_size_badged)
 
-            val animatorUpdateListener: ValueAnimator.AnimatorUpdateListener
-                    = ValueAnimator.AnimatorUpdateListener { animation ->
+            val animatorUpdateListener: ValueAnimator.AnimatorUpdateListener =
+                    ValueAnimator.AnimatorUpdateListener { animation ->
                 val strokeWidth = animation.animatedValue as Int
                 ring.setStroke(strokeWidth, ringColor)
                 val newSize = baseSize + strokeWidth * 2
@@ -199,8 +220,8 @@
             growAnimation.duration = IMPORTANCE_ANIM_GROW_DURATION
             growAnimation.addUpdateListener(animatorUpdateListener)
 
-            val shrinkAnimation: ValueAnimator
-                    = ValueAnimator.ofInt(largeThickness, standardThickness)
+            val shrinkAnimation: ValueAnimator =
+                    ValueAnimator.ofInt(largeThickness, standardThickness)
             shrinkAnimation.duration = IMPORTANCE_ANIM_SHRINK_DURATION
             shrinkAnimation.startDelay = IMPORTANCE_ANIM_SHRINK_DELAY
             shrinkAnimation.interpolator = OVERSHOOT
@@ -208,15 +229,14 @@
             shrinkAnimation.addListener(object : AnimatorListenerAdapter() {
                 override fun onAnimationStart(animation: Animator?) {
                     // Shrink the badge bg so that it doesn't peek behind the animation
-                    bg.setSize(baseSize, baseSize);
-                    conversationIconBadgeBg.invalidate();
+                    bg.setSize(baseSize, baseSize)
+                    conversationIconBadgeBg.invalidate()
                 }
 
                 override fun onAnimationEnd(animation: Animator?) {
                     // Reset bg back to normal size
-                    bg.setSize(bgSize, bgSize);
-                    conversationIconBadgeBg.invalidate();
-
+                    bg.setSize(bgSize, bgSize)
+                    conversationIconBadgeBg.invalidate()
                 }
             })
 
@@ -228,20 +248,20 @@
                     R.dimen.conversation_onboarding_bullet_gap_width)
             val description = SpannableStringBuilder()
             description.append(context.getText(R.string.priority_onboarding_show_at_top_text),
-                    BulletSpan(gapWidth),  /* flags */0)
+                    BulletSpan(gapWidth), /* flags */0)
             description.append(System.lineSeparator())
             description.append(context.getText(R.string.priority_onboarding_show_avatar_text),
-                    BulletSpan(gapWidth),  /* flags */0)
+                    BulletSpan(gapWidth), /* flags */0)
             if (showsAsBubble) {
                 description.append(System.lineSeparator())
                 description.append(context.getText(
                         R.string.priority_onboarding_appear_as_bubble_text),
-                        BulletSpan(gapWidth),  /* flags */0)
+                        BulletSpan(gapWidth), /* flags */0)
             }
             if (ignoresDnd) {
                 description.append(System.lineSeparator())
                 description.append(context.getText(R.string.priority_onboarding_ignores_dnd_text),
-                        BulletSpan(gapWidth),  /* flags */0)
+                        BulletSpan(gapWidth), /* flags */0)
             }
             findViewById<TextView>(R.id.behaviors).setText(description)
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 970efd5..f6c1b1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -456,6 +456,7 @@
     private long mNumHeadsUp;
     private NotificationStackScrollLayoutController.TouchHandler mTouchHandler;
     private final FeatureFlags mFeatureFlags;
+    private boolean mShouldUseSplitNotificationShade;
 
     private final ExpandableView.OnHeightChangedListener mOnChildHeightChangedListener =
             new ExpandableView.OnHeightChangedListener() {
@@ -500,7 +501,8 @@
         super(context, attrs, 0, 0);
         Resources res = getResources();
         mSectionsManager = notificationSectionsManager;
-
+        mFeatureFlags = featureFlags;
+        mShouldUseSplitNotificationShade = shouldUseSplitNotificationShade(mFeatureFlags, res);
         mSectionsManager.initialize(this, LayoutInflater.from(context));
         mSections = mSectionsManager.createSectionsForBuckets();
 
@@ -533,7 +535,6 @@
         mGroupMembershipManager = groupMembershipManager;
         mGroupExpansionManager = groupExpansionManager;
         mStatusbarStateController = statusbarStateController;
-        mFeatureFlags = featureFlags;
     }
 
     void initializeForegroundServiceSection(ForegroundServiceDungeonView fgsSectionView) {
@@ -1164,7 +1165,7 @@
                 if (stackStartPosition <= stackEndPosition) {
                     stackHeight = stackEndPosition;
                 } else {
-                    if (shouldUseSplitNotificationShade(mFeatureFlags, getResources())) {
+                    if (mShouldUseSplitNotificationShade) {
                         // This prevents notifications from being collapsed when QS is expanded.
                         stackHeight = (int) height;
                     } else {
@@ -1552,8 +1553,10 @@
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        mStatusBarHeight = getResources().getDimensionPixelOffset(R.dimen.status_bar_height);
-        float densityScale = getResources().getDisplayMetrics().density;
+        Resources res = getResources();
+        mShouldUseSplitNotificationShade = shouldUseSplitNotificationShade(mFeatureFlags, res);
+        mStatusBarHeight = res.getDimensionPixelOffset(R.dimen.status_bar_height);
+        float densityScale = res.getDisplayMetrics().density;
         mSwipeHelper.setDensityScale(densityScale);
         float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
         mSwipeHelper.setPagingTouchSlop(pagingTouchSlop);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 713daaa..6b69103 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -533,6 +533,17 @@
         }
     }
 
+    /**
+     * Apply keyguard configuration from the currently active resources. This can be called when the
+     * device configuration changes, to re-apply some resources that are qualified on the device
+     * configuration.
+     */
+    public void updateResources() {
+        if (mKeyguardViewController != null) {
+            mKeyguardViewController.updateResources();
+        }
+    }
+
     public void dump(PrintWriter pw) {
         pw.println("KeyguardBouncer");
         pw.println("  isShowing(): " + isShowing());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 6b144c6..25de551 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -152,6 +152,7 @@
     private boolean mDozing;
     private boolean mOnLockScreen;
     private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
+    private boolean mInNotificationIconShelf;
     private boolean mChangingViewPositions;
     private int mAddAnimationStartIndex = -1;
     private int mCannedAnimationStartIndex = -1;
@@ -702,6 +703,10 @@
         mLockScreenMode = lockScreenMode;
     }
 
+    public void setInNotificationIconShelf(boolean inShelf) {
+        mInNotificationIconShelf = inShelf;
+    }
+
     public class IconState extends ViewState {
         public static final int NO_VALUE = NotificationIconContainer.NO_VALUE;
         public float iconAppearAmount = 1.0f;
@@ -813,7 +818,7 @@
                     }
                 }
                 icon.setVisibleState(visibleState, animationsAllowed);
-                icon.setIconColor(mThemedTextColorPrimary,
+                icon.setIconColor(mInNotificationIconShelf ? mThemedTextColorPrimary : iconColor,
                         needsCannedAnimation && animationsAllowed);
                 if (animate) {
                     animateTo(icon, animationProperties);
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 cd71204..4ef6668 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -305,6 +305,7 @@
     // 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
     private final int mMaxKeyguardNotifications;
+    private boolean mShouldUseSplitNotificationShade;
     // Current max allowed keyguard notifications determined by measuring the panel
     private int mMaxAllowedKeyguardNotifications;
 
@@ -598,6 +599,8 @@
                 mKeyguardUserSwitcherEnabled && mResources.getBoolean(
                         R.bool.config_keyguard_user_switch_opens_qs_details);
         keyguardUpdateMonitor.setKeyguardQsUserSwitchEnabled(mKeyguardQsUserSwitchEnabled);
+        mShouldUseSplitNotificationShade =
+                Utils.shouldUseSplitNotificationShade(mFeatureFlags, mResources);
         mView.setWillNotDraw(!DEBUG);
         mLayoutInflater = layoutInflater;
         mFalsingManager = falsingManager;
@@ -736,7 +739,7 @@
 
         mView.setAccessibilityDelegate(mAccessibilityDelegate);
         // dynamically apply the split shade value overrides.
-        if (Utils.shouldUseSplitNotificationShade(mFeatureFlags, mResources)) {
+        if (mShouldUseSplitNotificationShade) {
             updateResources();
         }
     }
@@ -835,12 +838,13 @@
     public void updateResources() {
         int qsWidth = mResources.getDimensionPixelSize(R.dimen.qs_panel_width);
         int panelWidth = mResources.getDimensionPixelSize(R.dimen.notification_panel_width);
-
+        mShouldUseSplitNotificationShade =
+                Utils.shouldUseSplitNotificationShade(mFeatureFlags, mResources);
         // To change the constraints at runtime, all children of the ConstraintLayout must have ids
         ensureAllViewsHaveIds(mNotificationContainerParent);
         ConstraintSet constraintSet = new ConstraintSet();
         constraintSet.clone(mNotificationContainerParent);
-        if (Utils.shouldUseSplitNotificationShade(mFeatureFlags, mResources)) {
+        if (mShouldUseSplitNotificationShade) {
             // width = 0 to take up all available space within constraints
             qsWidth = 0;
             panelWidth = 0;
@@ -1915,7 +1919,7 @@
                 mBarState != KEYGUARD
                         && (!mQsExpanded
                             || mQsExpansionFromOverscroll
-                            || Utils.shouldUseSplitNotificationShade(mFeatureFlags, mResources)));
+                            || mShouldUseSplitNotificationShade));
 
         if (mKeyguardUserSwitcherController != null && mQsExpanded
                 && !mStackScrollerOverscrolling) {
@@ -1987,7 +1991,7 @@
 
     private float calculateQsTopPadding() {
         // in split shade mode we want notifications to be directly below status bar
-        if (Utils.shouldUseSplitNotificationShade(mFeatureFlags, mResources) && !mKeyguardShowing) {
+        if (mShouldUseSplitNotificationShade && !mKeyguardShowing) {
             return 0f;
         }
         if (mKeyguardShowing && (mQsExpandImmediate
@@ -2203,8 +2207,7 @@
             return true;
         }
 
-        return !Utils.shouldUseSplitNotificationShade(mFeatureFlags, mResources)
-                && (isInSettings() || mIsPanelCollapseOnQQS);
+        return !mShouldUseSplitNotificationShade && (isInSettings() || mIsPanelCollapseOnQQS);
     }
 
     @Override
@@ -2631,7 +2634,7 @@
         super.onTrackingStarted();
         if (mQsFullyExpanded) {
             mQsExpandImmediate = true;
-            if (!Utils.shouldUseSplitNotificationShade(mFeatureFlags, mResources)) {
+            if (!mShouldUseSplitNotificationShade) {
                 mNotificationStackScrollLayoutController.setShouldShowShelfOnly(true);
             }
         }
@@ -2882,7 +2885,7 @@
      */
     protected void updateHorizontalPanelPosition(float x) {
         if (mNotificationStackScrollLayoutController.getWidth() * 1.75f > mView.getWidth()
-                || Utils.shouldUseSplitNotificationShade(mFeatureFlags, mResources)) {
+                || mShouldUseSplitNotificationShade) {
             resetHorizontalPanelPosition();
             return;
         }
@@ -3573,7 +3576,7 @@
         @Override
         public void onOverscrollTopChanged(float amount, boolean isRubberbanded) {
             // When in split shade, overscroll shouldn't carry through to QS
-            if (Utils.shouldUseSplitNotificationShade(mFeatureFlags, mResources)) {
+            if (mShouldUseSplitNotificationShade) {
                 return;
             }
             cancelQsAnimation();
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 5045e95..0e1fe22 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -22,6 +22,7 @@
 import static android.app.StatusBarManager.WindowVisibleState;
 import static android.app.StatusBarManager.windowStateToString;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
+import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT;
 import static android.view.InsetsState.ITYPE_STATUS_BAR;
 import static android.view.InsetsState.containsType;
 import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
@@ -46,6 +47,7 @@
 import static com.android.systemui.statusbar.phone.BarTransitions.TransitionMode;
 import static com.android.wm.shell.bubbles.BubbleController.TASKBAR_CHANGED_BROADCAST;
 
+import android.animation.ValueAnimator;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
@@ -74,6 +76,7 @@
 import android.content.res.Configuration;
 import android.graphics.Point;
 import android.graphics.PointF;
+import android.graphics.RectF;
 import android.media.AudioAttributes;
 import android.metrics.LogMaker;
 import android.net.Uri;
@@ -144,6 +147,7 @@
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
+import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.charging.WirelessChargingAnimation;
@@ -178,6 +182,7 @@
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.statusbar.AutoHideUiElement;
 import com.android.systemui.statusbar.BackDropView;
+import com.android.systemui.statusbar.CircleReveal;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.CrossFadeHelper;
 import com.android.systemui.statusbar.FeatureFlags;
@@ -201,6 +206,8 @@
 import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.charging.ChargingRippleView;
+import com.android.systemui.statusbar.charging.WiredChargingRippleController;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
@@ -376,7 +383,11 @@
     private boolean mWakeUpComingFromTouch;
     private PointF mWakeUpTouchLocation;
     private LightRevealScrim mLightRevealScrim;
+    private ChargingRippleView mChargingRipple;
+    private WiredChargingRippleController mChargingRippleAnimationController;
     private PowerButtonReveal mPowerButtonReveal;
+    private CircleReveal mCircleReveal;
+    private ValueAnimator mCircleRevealAnimator = ValueAnimator.ofFloat(0f, 1f);
 
     private final Object mQueueLock = new Object();
 
@@ -737,6 +748,7 @@
             VisualStabilityManager visualStabilityManager,
             DeviceProvisionedController deviceProvisionedController,
             NavigationBarController navigationBarController,
+            AccessibilityFloatingMenuController accessibilityFloatingMenuController,
             Lazy<AssistManager> assistManagerLazy,
             ConfigurationController configurationController,
             NotificationShadeWindowController notificationShadeWindowController,
@@ -775,6 +787,7 @@
             StatusBarTouchableRegionManager statusBarTouchableRegionManager,
             NotificationIconAreaController notificationIconAreaController,
             BrightnessSlider.Factory brightnessSliderFactory,
+            WiredChargingRippleController chargingRippleAnimationController,
             FeatureFlags featureFlags) {
         super(context);
         mNotificationsController = notificationsController;
@@ -853,6 +866,7 @@
         mDemoModeController = demoModeController;
         mNotificationIconAreaController = notificationIconAreaController;
         mBrightnessSliderFactory = brightnessSliderFactory;
+        mChargingRippleAnimationController = chargingRippleAnimationController;
         mFeatureFlags = featureFlags;
 
         mExpansionChangedListeners = new ArrayList<>();
@@ -1196,8 +1210,11 @@
         mScrimController.attachViews(scrimBehind, scrimInFront, scrimForBubble);
 
         mLightRevealScrim = mNotificationShadeWindowView.findViewById(R.id.light_reveal_scrim);
+        mChargingRippleAnimationController.setViewHost(mNotificationShadeWindowView);
 
-        if (mFeatureFlags.useNewLockscreenAnimations() && mDozeParameters.getAlwaysOn()) {
+
+        if (mFeatureFlags.useNewLockscreenAnimations()
+                && (mDozeParameters.getAlwaysOn() || mDozeParameters.isQuickPickupEnabled())) {
             mLightRevealScrim.setVisibility(View.VISIBLE);
             mLightRevealScrim.setRevealEffect(LiftReveal.INSTANCE);
         } else {
@@ -2963,6 +2980,9 @@
         if (mBrightnessMirrorController != null) {
             mBrightnessMirrorController.updateResources();
         }
+        if (mStatusBarKeyguardViewManager != null) {
+            mStatusBarKeyguardViewManager.updateResources();
+        }
 
         mPowerButtonReveal = new PowerButtonReveal(mContext.getResources().getDimensionPixelSize(
                 R.dimen.global_actions_top_padding));
@@ -3341,6 +3361,9 @@
         mNotificationPanelViewController.fadeOut(0, FADE_KEYGUARD_DURATION_PULSING,
                 ()-> {
                 hideKeyguard();
+                if (shouldShowCircleReveal()) {
+                    startCircleReveal();
+                }
                 mStatusBarKeyguardViewManager.onKeyguardFadedAway();
             }).start();
     }
@@ -3654,15 +3677,16 @@
         updateQsExpansionEnabled();
         mKeyguardViewMediator.setDozing(mDozing);
 
-        final boolean usePowerButtonEffect =
-                (isDozing && mWakefulnessLifecycle.getLastSleepReason()
-                        == PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON)
-                        || (!isDozing && mWakefulnessLifecycle.getLastWakeReason()
-                        == PowerManager.WAKE_REASON_POWER_BUTTON);
-
-        mLightRevealScrim.setRevealEffect(usePowerButtonEffect
-                ? mPowerButtonReveal
-                : LiftReveal.INSTANCE);
+        if (!isDozing && shouldShowCircleReveal()) {
+            startCircleReveal();
+        } else if ((isDozing && mWakefulnessLifecycle.getLastSleepReason()
+                == PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON)
+                || (!isDozing && mWakefulnessLifecycle.getLastWakeReason()
+                == PowerManager.WAKE_REASON_POWER_BUTTON)) {
+            mLightRevealScrim.setRevealEffect(mPowerButtonReveal);
+        } else if (!mCircleRevealAnimator.isRunning()) {
+            mLightRevealScrim.setRevealEffect(LiftReveal.INSTANCE);
+        }
 
         mNotificationsController.requestNotificationUpdate("onDozingChanged");
         updateDozingState();
@@ -3672,6 +3696,22 @@
         Trace.endSection();
     }
 
+    private void startCircleReveal() {
+        mLightRevealScrim.setRevealEffect(mCircleReveal);
+        mCircleRevealAnimator.cancel();
+        mCircleRevealAnimator.addUpdateListener(animation ->
+                mLightRevealScrim.setRevealAmount(
+                        (float) mCircleRevealAnimator.getAnimatedValue()));
+        mCircleRevealAnimator.setDuration(900);
+        mCircleRevealAnimator.start();
+    }
+
+    private boolean shouldShowCircleReveal() {
+        return mCircleReveal != null && !mCircleRevealAnimator.isRunning()
+                && mKeyguardUpdateMonitor.isUdfpsEnrolled()
+                && mBiometricUnlockController.getBiometricType() == FINGERPRINT;
+    }
+
     private void updateKeyguardState() {
         mKeyguardStateController.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(),
                 mStatusBarKeyguardViewManager.isOccluded());
@@ -4158,6 +4198,15 @@
                 mBiometricUnlockController.getBiometricType());
     }
 
+    /**
+     * Set the location of the sensor on UDFPS if existent.
+     */
+    public void setSensorRect(RectF rect) {
+        final float startRadius = (rect.right - rect.left) / 2f;
+        mCircleReveal = new CircleReveal(rect.centerX(), rect.centerY(),
+                startRadius, rect.centerY() - startRadius);
+    }
+
     @VisibleForTesting
     public void updateScrimController() {
         Trace.beginSection("StatusBar#updateScrimController");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 8620376..8fe9a48 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -66,7 +66,11 @@
     /**
      * Display the no calling & SMS icons.
      */
-    void setCallIndicatorIcons(String slot, List<CallIndicatorIconState> states);
+    void setCallStrengthIcons(String slot, List<CallIndicatorIconState> states);
+    /**
+     * Display the no calling & SMS icons.
+     */
+    void setNoCallingIcons(String slot, List<CallIndicatorIconState> states);
     public void setIconVisibility(String slot, boolean b);
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
index f0c8527..6404aea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -219,27 +219,56 @@
     }
 
     /**
-     * Accept a list of CallIndicatorIconStates, and show them in the same slot
-     * @param slot StatusBar slot
+     * Accept a list of CallIndicatorIconStates, and show the call strength icons.
+     * @param slot StatusBar slot for the call strength icons
      * @param states All of the no Calling & SMS icon states
      */
     @Override
-    public void setCallIndicatorIcons(String slot, List<CallIndicatorIconState> states) {
-        Slot noCallingSlot = getSlot(slot);
-        int slotIndex = getSlotIndex(slot);
+    public void setCallStrengthIcons(String slot, List<CallIndicatorIconState> states) {
+        Slot callStrengthSlot = getSlot(slot);
+        int callStrengthSlotIndex = getSlotIndex(slot);
+        Collections.reverse(states);
         for (CallIndicatorIconState state : states) {
-            StatusBarIconHolder holder = noCallingSlot.getHolderForTag(state.subId);
-            if (holder == null) {
-                holder = StatusBarIconHolder.fromCallIndicatorState(mContext, state);
-                setIcon(slotIndex, holder);
-            } else {
-                int resId = state.isNoCalling ? state.noCallingResId : state.callStrengthResId;
-                String contentDescription = state.isNoCalling
-                        ? state.noCallingDescription : state.callStrengthDescription;
-                holder.setIcon(new StatusBarIcon(UserHandle.SYSTEM, mContext.getPackageName(),
-                        Icon.createWithResource(mContext, resId), 0, 0, contentDescription));
-                setIcon(slotIndex, holder);
+            if (!state.isNoCalling) {
+                StatusBarIconHolder holder = callStrengthSlot.getHolderForTag(state.subId);
+                if (holder == null) {
+                    holder = StatusBarIconHolder.fromCallIndicatorState(mContext, state);
+                    setIcon(callStrengthSlotIndex, holder);
+                } else {
+                    holder.setIcon(new StatusBarIcon(UserHandle.SYSTEM, mContext.getPackageName(),
+                            Icon.createWithResource(mContext, state.callStrengthResId), 0, 0,
+                            state.callStrengthDescription));
+                    setIcon(callStrengthSlotIndex, holder);
+                }
             }
+            setIconVisibility(slot, !state.isNoCalling, state.subId);
+        }
+    }
+
+    /**
+     * Accept a list of CallIndicatorIconStates, and show the no calling icons.
+     * @param slot StatusBar slot for the no calling icons
+     * @param states All of the no Calling & SMS icon states
+     */
+    @Override
+    public void setNoCallingIcons(String slot, List<CallIndicatorIconState> states) {
+        Slot noCallingSlot = getSlot(slot);
+        int noCallingSlotIndex = getSlotIndex(slot);
+        Collections.reverse(states);
+        for (CallIndicatorIconState state : states) {
+            if (state.isNoCalling) {
+                StatusBarIconHolder holder = noCallingSlot.getHolderForTag(state.subId);
+                if (holder == null) {
+                    holder = StatusBarIconHolder.fromCallIndicatorState(mContext, state);
+                    setIcon(noCallingSlotIndex, holder);
+                } else {
+                    holder.setIcon(new StatusBarIcon(UserHandle.SYSTEM, mContext.getPackageName(),
+                            Icon.createWithResource(mContext, state.noCallingResId), 0, 0,
+                            state.noCallingDescription));
+                    setIcon(noCallingSlotIndex, holder);
+                }
+            }
+            setIconVisibility(slot, state.isNoCalling, state.subId);
         }
     }
 
@@ -282,9 +311,15 @@
         }
     }
 
+    /** */
     public void setIconVisibility(String slot, boolean visibility) {
+        setIconVisibility(slot, visibility, 0);
+    }
+
+    /** */
+    public void setIconVisibility(String slot, boolean visibility, int tag) {
         int index = getSlotIndex(slot);
-        StatusBarIconHolder holder = getIcon(index, 0);
+        StatusBarIconHolder holder = getIcon(index, tag);
         if (holder == null || holder.isVisible() == visibility) {
             return;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java
index a1a2d30..19db02a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java
@@ -83,7 +83,6 @@
         holder.mIcon = new StatusBarIcon(UserHandle.SYSTEM, context.getPackageName(),
                 Icon.createWithResource(context, resId), 0, 0, contentDescription);
         holder.mTag = state.subId;
-        holder.setVisible(true);
         return holder;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 81e24cc..c1f300b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -1084,6 +1084,17 @@
                 || mBouncer.isFullscreenBouncer();
     }
 
+    /**
+     * Apply keyguard configuration from the currently active resources. This can be called when the
+     * device configuration changes, to re-apply some resources that are qualified on the device
+     * configuration.
+     */
+    public void updateResources() {
+        if (mBouncer != null) {
+            mBouncer.updateResources();
+        }
+    }
+
     public void dump(PrintWriter pw) {
         pw.println("StatusBarKeyguardViewManager:");
         pw.println("  mShowing: " + mShowing);
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 9ee7b09..3445826 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
@@ -50,6 +50,7 @@
     private final String mSlotEthernet;
     private final String mSlotVpn;
     private final String mSlotNoCalling;
+    private final String mSlotCallStrength;
 
     private final Context mContext;
     private final StatusBarIconController mIconController;
@@ -83,6 +84,8 @@
         mSlotEthernet = mContext.getString(com.android.internal.R.string.status_bar_ethernet);
         mSlotVpn      = mContext.getString(com.android.internal.R.string.status_bar_vpn);
         mSlotNoCalling = mContext.getString(com.android.internal.R.string.status_bar_no_calling);
+        mSlotCallStrength =
+                mContext.getString(com.android.internal.R.string.status_bar_call_strength);
         mActivityEnabled = mContext.getResources().getBoolean(R.bool.config_showActivity);
 
         mIconController = iconController;
@@ -212,8 +215,10 @@
             state.callStrengthResId = statusIcon.icon;
             state.callStrengthDescription = statusIcon.contentDescription;
         }
-        mIconController.setCallIndicatorIcons(
-                mSlotNoCalling, CallIndicatorIconState.copyStates(mCallIndicatorStates));
+        mIconController.setCallStrengthIcons(mSlotCallStrength,
+                CallIndicatorIconState.copyStates(mCallIndicatorStates));
+        mIconController.setNoCallingIcons(mSlotNoCalling,
+                CallIndicatorIconState.copyStates(mCallIndicatorStates));
     }
 
     @Override
@@ -300,6 +305,7 @@
 
         mIconController.removeAllIconsForSlot(mSlotMobile);
         mIconController.removeAllIconsForSlot(mSlotNoCalling);
+        mIconController.removeAllIconsForSlot(mSlotCallStrength);
         mMobileStates.clear();
         List<CallIndicatorIconState> noCallingStates = new ArrayList<CallIndicatorIconState>();
         noCallingStates.addAll(mCallIndicatorStates);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index b572c57..4f32712 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -29,6 +29,7 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.InitController;
+import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.classifier.FalsingCollector;
@@ -59,6 +60,7 @@
 import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.charging.WiredChargingRippleController;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
@@ -164,6 +166,7 @@
             VisualStabilityManager visualStabilityManager,
             DeviceProvisionedController deviceProvisionedController,
             NavigationBarController navigationBarController,
+            AccessibilityFloatingMenuController accessibilityFloatingMenuController,
             Lazy<AssistManager> assistManagerLazy,
             ConfigurationController configurationController,
             NotificationShadeWindowController notificationShadeWindowController,
@@ -202,6 +205,7 @@
             StatusBarTouchableRegionManager statusBarTouchableRegionManager,
             NotificationIconAreaController notificationIconAreaController,
             BrightnessSlider.Factory brightnessSliderFactory,
+            WiredChargingRippleController chargingRippleAnimationController,
             FeatureFlags featureFlags) {
         return new StatusBar(
                 context,
@@ -245,6 +249,7 @@
                 visualStabilityManager,
                 deviceProvisionedController,
                 navigationBarController,
+                accessibilityFloatingMenuController,
                 assistManagerLazy,
                 configurationController,
                 notificationShadeWindowController,
@@ -282,6 +287,7 @@
                 statusBarTouchableRegionManager,
                 notificationIconAreaController,
                 brightnessSliderFactory,
+                chargingRippleAnimationController,
                 featureFlags);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
index fd19528..3892f31 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
+++ b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
@@ -26,6 +26,7 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.UserHandle;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.ImageView;
@@ -43,6 +44,7 @@
  * directly. Instead, use {@link ToastFactory#createToast}.
  */
 public class SystemUIToast implements ToastPlugin.Toast {
+    static final String TAG = "SystemUIToast";
     final Context mContext;
     final CharSequence mText;
     final ToastPlugin.Toast mPluginToast;
@@ -225,8 +227,12 @@
             int userId) {
         final ApplicationsState appState =
                 ApplicationsState.getInstance((Application) context.getApplicationContext());
+        if (!appState.isUserAdded(userId)) {
+            Log.d(TAG, "user hasn't been fully initialized, not showing an app icon for "
+                    + "packageName=" + packageName);
+            return null;
+        }
         final AppEntry appEntry = appState.getEntry(packageName, userId);
-
         if (!ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER.filterApp(appEntry)) {
             return null;
         }
@@ -237,6 +243,5 @@
         Bitmap iconBmp = iconFactory.createBadgedIconBitmap(
                 appInfo.loadUnbadgedIcon(context.getPackageManager()), user, true).icon;
         return new BitmapDrawable(context.getResources(), iconBmp);
-
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/util/RoundedCornerProgressDrawable.kt b/packages/SystemUI/src/com/android/systemui/util/RoundedCornerProgressDrawable.kt
index 6aadd10..dc86d58 100644
--- a/packages/SystemUI/src/com/android/systemui/util/RoundedCornerProgressDrawable.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/RoundedCornerProgressDrawable.kt
@@ -17,8 +17,6 @@
 package com.android.systemui.util
 
 import android.content.res.Resources
-import android.graphics.Canvas
-import android.graphics.Path
 import android.graphics.Rect
 import android.graphics.drawable.Drawable
 import android.graphics.drawable.DrawableWrapper
@@ -43,53 +41,25 @@
         private const val MAX_LEVEL = 10000 // Taken from Drawable
     }
 
-    private var clipPath: Path = Path()
-
-    init {
-        setClipPath(Rect())
-    }
-
     override fun onLayoutDirectionChanged(layoutDirection: Int): Boolean {
         onLevelChange(level)
         return super.onLayoutDirectionChanged(layoutDirection)
     }
 
     override fun onBoundsChange(bounds: Rect) {
-        setClipPath(bounds)
         super.onBoundsChange(bounds)
         onLevelChange(level)
     }
 
-    private fun setClipPath(bounds: Rect) {
-        clipPath.reset()
-        clipPath.addRoundRect(
-                bounds.left.toFloat(),
-                bounds.top.toFloat(),
-                bounds.right.toFloat(),
-                bounds.bottom.toFloat(),
-                bounds.height().toFloat() / 2,
-                bounds.height().toFloat() / 2,
-                Path.Direction.CW
-        )
-    }
-
     override fun onLevelChange(level: Int): Boolean {
         val db = drawable?.bounds!!
-        val width = bounds.width() * level / MAX_LEVEL
-        // Extra space on the left to keep the rounded shape on the right end
-        val leftBound = bounds.left - bounds.height()
-        drawable?.setBounds(leftBound, db.top, bounds.left + width, db.bottom)
+        // On 0, the width is bounds.height (a circle), and on MAX_LEVEL, the width is bounds.width
+        val width = bounds.height() + (bounds.width() - bounds.height()) * level / MAX_LEVEL
+        drawable?.setBounds(bounds.left, db.top, bounds.left + width, db.bottom)
         return super.onLevelChange(level)
     }
 
-    override fun draw(canvas: Canvas) {
-        canvas.save()
-        canvas.clipPath(clipPath)
-        super.draw(canvas)
-        canvas.restore()
-    }
-
-    override fun getConstantState(): ConstantState? {
+    override fun getConstantState(): ConstantState {
         // This should not be null as it was created with a state in the constructor.
         return RoundedCornerState(super.getConstantState()!!)
     }
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index 3f4ec85..ddfa63a 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -81,7 +81,7 @@
 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.ShellTransitions;
 import com.android.wm.shell.transition.Transitions;
 
 import java.util.Optional;
@@ -399,8 +399,8 @@
 
     @WMSingleton
     @Provides
-    static RemoteTransitions provideRemoteTransitions(Transitions transitions) {
-        return Transitions.asRemoteTransitions(transitions);
+    static ShellTransitions provideRemoteTransitions(Transitions transitions) {
+        return transitions.asRemoteTransitions();
     }
 
     @WMSingleton
@@ -509,27 +509,33 @@
 
     @WMSingleton
     @Provides
-    static ShellInit provideShellInit(DisplayImeController displayImeController,
+    static ShellInit provideShellInit(ShellInitImpl impl) {
+        return impl.asShellInit();
+    }
+
+    @WMSingleton
+    @Provides
+    static ShellInitImpl provideShellInitImpl(DisplayImeController displayImeController,
             DragAndDropController dragAndDropController,
             ShellTaskOrganizer shellTaskOrganizer,
             Optional<LegacySplitScreenController> legacySplitScreenOptional,
             Optional<SplitScreenController> splitScreenOptional,
             Optional<AppPairsController> appPairsOptional,
-            Optional<StartingSurface> startingSurface,
             Optional<PipTouchHandler> pipTouchHandlerOptional,
             FullscreenTaskListener fullscreenTaskListener,
             Transitions transitions,
+            StartingWindowController startingWindow,
             @ShellMainThread ShellExecutor mainExecutor) {
-        return ShellInitImpl.create(displayImeController,
+        return new ShellInitImpl(displayImeController,
                 dragAndDropController,
                 shellTaskOrganizer,
                 legacySplitScreenOptional,
                 splitScreenOptional,
                 appPairsOptional,
-                startingSurface,
                 pipTouchHandlerOptional,
                 fullscreenTaskListener,
                 transitions,
+                startingWindow,
                 mainExecutor);
     }
 
@@ -539,7 +545,13 @@
      */
     @WMSingleton
     @Provides
-    static Optional<ShellCommandHandler> provideShellCommandHandler(
+    static Optional<ShellCommandHandler> provideShellCommandHandler(ShellCommandHandlerImpl impl) {
+        return Optional.of(impl.asShellCommandHandler());
+    }
+
+    @WMSingleton
+    @Provides
+    static ShellCommandHandlerImpl provideShellCommandHandlerImpl(
             ShellTaskOrganizer shellTaskOrganizer,
             Optional<LegacySplitScreenController> legacySplitScreenOptional,
             Optional<SplitScreenController> splitScreenOptional,
@@ -548,8 +560,8 @@
             Optional<HideDisplayCutoutController> hideDisplayCutout,
             Optional<AppPairsController> appPairsOptional,
             @ShellMainThread ShellExecutor mainExecutor) {
-        return Optional.of(ShellCommandHandlerImpl.create(shellTaskOrganizer,
+        return new ShellCommandHandlerImpl(shellTaskOrganizer,
                 legacySplitScreenOptional, splitScreenOptional, pipOptional, oneHandedOptional,
-                hideDisplayCutout, appPairsOptional, mainExecutor));
+                hideDisplayCutout, appPairsOptional, mainExecutor);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java
index 64632af..714f1f2 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java
@@ -16,6 +16,9 @@
 
 package com.android.keyguard;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -26,11 +29,14 @@
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
+import android.view.Gravity;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
 
+import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 
-import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -46,7 +52,7 @@
 
     @Mock
     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
-    @Mock
+
     private KeyguardHostView mKeyguardHostView;
     @Mock
     private AudioManager mAudioManager;
@@ -66,6 +72,10 @@
 
     @Before
     public void setup() {
+        mContext.ensureTestableResources();
+
+        mKeyguardHostView = new KeyguardHostView(mContext);
+
         when(mKeyguardSecurityContainerControllerFactory.create(any(
                 KeyguardSecurityContainer.SecurityCallback.class)))
                 .thenReturn(mKeyguardSecurityContainerController);
@@ -76,10 +86,10 @@
 
     @Test
     public void testHasDismissActions() {
-        Assert.assertFalse("Action not set yet", mKeyguardHostViewController.hasDismissActions());
+        assertFalse("Action not set yet", mKeyguardHostViewController.hasDismissActions());
         mKeyguardHostViewController.setOnDismissAction(mock(OnDismissAction.class),
                 null /* cancelAction */);
-        Assert.assertTrue("Action should exist", mKeyguardHostViewController.hasDismissActions());
+        assertTrue("Action should exist", mKeyguardHostViewController.hasDismissActions());
     }
 
     @Test
@@ -87,4 +97,31 @@
         mKeyguardHostViewController.onStartingToHide();
         verify(mKeyguardSecurityContainerController).onStartingToHide();
     }
+
+    @Test
+    public void testGravityReappliedOnConfigurationChange() {
+        FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        mKeyguardHostView.setLayoutParams(lp);
+
+        // Set initial gravity
+        mContext.getOrCreateTestableResources().addOverride(R.integer.keyguard_host_view_gravity,
+                Gravity.CENTER);
+
+        // Kick off the initial pass...
+        mKeyguardHostViewController.init();
+        assertEquals(
+                ((FrameLayout.LayoutParams) mKeyguardHostView.getLayoutParams()).gravity,
+                Gravity.CENTER);
+
+        // Now simulate a config change
+        mContext.getOrCreateTestableResources().addOverride(R.integer.keyguard_host_view_gravity,
+                Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
+
+        mKeyguardHostViewController.updateResources();
+        assertEquals(
+                ((FrameLayout.LayoutParams) mKeyguardHostView.getLayoutParams()).gravity,
+                Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index e35e987..52e2016 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -50,6 +50,7 @@
 import android.content.pm.ServiceInfo;
 import android.hardware.biometrics.BiometricManager;
 import android.hardware.biometrics.BiometricSourceType;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
 import android.hardware.face.FaceManager;
 import android.hardware.face.FaceSensorProperties;
@@ -192,9 +193,19 @@
 
         // IBiometricsFace@1.0 does not support detection, only authentication.
         when(mFaceSensorProperties.isEmpty()).thenReturn(false);
+
+        final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
+        componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */,
+                "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */,
+                "00000001" /* serialNumber */, "" /* softwareVersion */));
+        componentInfo.add(new ComponentInfoInternal("matchingAlgorithm" /* componentId */,
+                "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */,
+                "vendor/version/revision" /* softwareVersion */));
+
         when(mFaceSensorProperties.get(anyInt())).thenReturn(new FaceSensorPropertiesInternal(
                 0 /* id */,
                 FaceSensorProperties.STRENGTH_STRONG, 1 /* maxTemplatesAllowed */,
+                componentInfo, FaceSensorProperties.TYPE_UNKNOWN,
                 false /* supportsFaceDetection */, true /* supportsSelfIllumination */,
                 false /* resetLockoutRequiresChallenge */));
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java b/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java
index e1ddaad..daa896c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java
@@ -41,6 +41,7 @@
 import android.view.SurfaceHolder;
 
 import com.android.systemui.glwallpaper.ImageWallpaperRenderer;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 
 import org.junit.Before;
 import org.junit.Ignore;
@@ -99,7 +100,7 @@
     }
 
     private ImageWallpaper createImageWallpaper() {
-        return new ImageWallpaper() {
+        return new ImageWallpaper(mock(StatusBarStateController.class)) {
             @Override
             public Engine onCreateEngine() {
                 return new GLEngine(mHandler) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityButtonModeObserverTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityButtonModeObserverTest.java
new file mode 100644
index 0000000..01b7ade
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityButtonModeObserverTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility;
+
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.provider.Settings;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+public class AccessibilityButtonModeObserverTest extends SysuiTestCase {
+
+    @Rule
+    public MockitoRule mockito = MockitoJUnit.rule();
+
+    @Mock
+    private AccessibilityButtonModeObserver.ModeChangedListener mListener;
+
+    private AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
+
+    private static final int TEST_A11Y_BTN_MODE_VALUE =
+            Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
+
+    @Before
+    public void setUp() {
+        Settings.Secure.putInt(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
+                Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR);
+        mAccessibilityButtonModeObserver = new AccessibilityButtonModeObserver(mContext);
+    }
+
+    @Test
+    public void onChange_haveListener_invokeCallback() {
+        mAccessibilityButtonModeObserver.addListener(mListener);
+        Settings.Secure.putInt(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_BUTTON_MODE, TEST_A11Y_BTN_MODE_VALUE);
+
+        mAccessibilityButtonModeObserver.mContentObserver.onChange(false);
+
+        verify(mListener).onAccessibilityButtonModeChanged(TEST_A11Y_BTN_MODE_VALUE);
+    }
+
+    @Test
+    public void onChange_noListener_noInvokeCallback() {
+        mAccessibilityButtonModeObserver.addListener(mListener);
+        mAccessibilityButtonModeObserver.removeListener(mListener);
+        Settings.Secure.putInt(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_BUTTON_MODE, TEST_A11Y_BTN_MODE_VALUE);
+
+        mAccessibilityButtonModeObserver.mContentObserver.onChange(false);
+
+        verify(mListener, never()).onAccessibilityButtonModeChanged(anyInt());
+    }
+
+    @Test
+    public void getCurrentAccessibilityButtonMode_expectedValue() {
+        Settings.Secure.putInt(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_BUTTON_MODE, TEST_A11Y_BTN_MODE_VALUE);
+
+        final int actualValue =
+                mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode();
+
+        assertThat(actualValue).isEqualTo(TEST_A11Y_BTN_MODE_VALUE);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityButtonTargetsObserverTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityButtonTargetsObserverTest.java
new file mode 100644
index 0000000..1e49fc9
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityButtonTargetsObserverTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.provider.Settings;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+/** Test for {@link AccessibilityButtonTargetsObserver}. */
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+public class AccessibilityButtonTargetsObserverTest extends SysuiTestCase {
+
+    @Rule
+    public MockitoRule mockito = MockitoJUnit.rule();
+
+    @Mock
+    private AccessibilityButtonTargetsObserver.TargetsChangedListener mListener;
+
+    private AccessibilityButtonTargetsObserver mAccessibilityButtonTargetsObserver;
+
+    private static final String TEST_A11Y_BTN_TARGETS = "Magnification";
+
+    @Before
+    public void setUp() {
+        mAccessibilityButtonTargetsObserver = new AccessibilityButtonTargetsObserver(mContext);
+    }
+
+    @Test
+    public void onChange_haveListener_invokeCallback() {
+        mAccessibilityButtonTargetsObserver.addListener(mListener);
+        Settings.Secure.putString(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, TEST_A11Y_BTN_TARGETS);
+
+        mAccessibilityButtonTargetsObserver.mContentObserver.onChange(false);
+
+        verify(mListener).onAccessibilityButtonTargetsChanged(TEST_A11Y_BTN_TARGETS);
+    }
+
+    @Test
+    public void onChange_listenerRemoved_noInvokeCallback() {
+        mAccessibilityButtonTargetsObserver.addListener(mListener);
+        mAccessibilityButtonTargetsObserver.removeListener(mListener);
+        Settings.Secure.putString(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, TEST_A11Y_BTN_TARGETS);
+
+        mAccessibilityButtonTargetsObserver.mContentObserver.onChange(false);
+
+        verify(mListener, never()).onAccessibilityButtonTargetsChanged(anyString());
+    }
+
+    @Test
+    public void getCurrentAccessibilityButtonTargets_expectedValue() {
+        Settings.Secure.putString(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, TEST_A11Y_BTN_TARGETS);
+
+        final String actualValue =
+                mAccessibilityButtonTargetsObserver.getCurrentAccessibilityButtonTargets();
+
+        assertThat(actualValue).isEqualTo(TEST_A11Y_BTN_TARGETS);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MotionEventHelper.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MotionEventHelper.java
index 92dad9b..550e77d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MotionEventHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MotionEventHelper.java
@@ -23,11 +23,11 @@
 import java.util.ArrayList;
 import java.util.List;
 
-class MotionEventHelper {
+public class MotionEventHelper {
     @GuardedBy("this")
     private final List<MotionEvent> mMotionEvents = new ArrayList<>();
 
-    void recycleEvents() {
+    public void recycleEvents() {
         for (MotionEvent event:mMotionEvents) {
             event.recycle();
         }
@@ -36,7 +36,7 @@
         }
     }
 
-    MotionEvent obtainMotionEvent(long downTime, long eventTime, int action, float x,
+    public MotionEvent obtainMotionEvent(long downTime, long eventTime, int action, float x,
             float y) {
         MotionEvent event = MotionEvent.obtain(downTime, eventTime, action, x, y, 0);
         synchronized (this) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/SecureSettingsContentObserverTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/SecureSettingsContentObserverTest.java
new file mode 100644
index 0000000..5b1c441
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/SecureSettingsContentObserverTest.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.systemui.accessibility;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Test for {@link SecureSettingsContentObserver}. */
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+public class SecureSettingsContentObserverTest extends SysuiTestCase {
+
+    private FakeSecureSettingsContentObserver mTestObserver;
+
+    @Before
+    public void setUpObserver() {
+        mTestObserver = new FakeSecureSettingsContentObserver(mContext,
+                Settings.Secure.ACCESSIBILITY_BUTTON_MODE);
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void addNullListener_throwNPE() {
+        mTestObserver.addListener(null);
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void removeNullListener_throwNPE() {
+        mTestObserver.removeListener(null);
+    }
+
+    @Test
+    public void checkValue() {
+        Settings.Secure.putInt(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_BUTTON_MODE, 1);
+
+        assertThat(mTestObserver.getSettingsValue()).isEqualTo("1");
+    }
+
+
+    private static class FakeSecureSettingsContentObserver extends
+            SecureSettingsContentObserver<Object> {
+
+        protected FakeSecureSettingsContentObserver(Context context,
+                String secureSettingsKey) {
+            super(context, secureSettingsKey);
+        }
+
+        @Override
+        void onValueChanged(Object listener, String value) {
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
new file mode 100644
index 0000000..a83f038
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.floatingmenu;
+
+import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
+import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.provider.Settings;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.accessibility.AccessibilityManager;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
+import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+/** Test for {@link AccessibilityFloatingMenuController}. */
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
+
+    private static final String TEST_A11Y_BTN_TARGETS = "Magnification";
+
+    @Rule
+    public MockitoRule mockito = MockitoJUnit.rule();
+
+    private AccessibilityFloatingMenuController mController;
+    private AccessibilityButtonTargetsObserver mTargetsObserver;
+    private AccessibilityButtonModeObserver mModeObserver;
+    @Mock
+    private AccessibilityManager mMockA11yManager;
+
+    @Test
+    public void initController_registerListeners() {
+        mController = setUpController();
+
+        verify(mTargetsObserver).addListener(
+                any(AccessibilityButtonTargetsObserver.TargetsChangedListener.class));
+        verify(mModeObserver).addListener(
+                any(AccessibilityButtonModeObserver.ModeChangedListener.class));
+        verify(mMockA11yManager).addAccessibilityStateChangeListener(any(
+                AccessibilityManager.AccessibilityStateChangeListener.class));
+    }
+
+    @Test
+    public void initController_accessibilityManagerEnabled_showWidget() {
+        Settings.Secure.putInt(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU);
+        Settings.Secure.putString(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, TEST_A11Y_BTN_TARGETS);
+        when(mMockA11yManager.isEnabled()).thenReturn(true);
+
+        mController = setUpController();
+
+        assertThat(mController.mFloatingMenu).isNotNull();
+        verify(mMockA11yManager).removeAccessibilityStateChangeListener(mController);
+    }
+
+    @Test
+    public void initController_accessibilityManagerDisabledThenCallbackToEnabled_showWidget() {
+        Settings.Secure.putInt(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU);
+        Settings.Secure.putString(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, TEST_A11Y_BTN_TARGETS);
+        when(mMockA11yManager.isEnabled()).thenReturn(false);
+
+        mController = setUpController();
+        mController.onAccessibilityStateChanged(true);
+
+        assertThat(mController.mFloatingMenu).isNotNull();
+        verify(mMockA11yManager).removeAccessibilityStateChangeListener(mController);
+    }
+
+    @Test
+    public void onAccessibilityButtonModeChanged_floatingModeAndHasButtonTargets_showWidget() {
+        Settings.Secure.putString(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, TEST_A11Y_BTN_TARGETS);
+        mController = setUpController();
+
+        mController.onAccessibilityButtonModeChanged(ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU);
+
+        assertThat(mController.mFloatingMenu).isNotNull();
+    }
+
+    @Test
+    public void onAccessibilityButtonModeChanged_floatingModeAndNoButtonTargets_destroyWidget() {
+        Settings.Secure.putString(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, "");
+        mController = setUpController();
+
+        mController.onAccessibilityButtonModeChanged(ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU);
+
+        assertThat(mController.mFloatingMenu).isNull();
+    }
+
+    @Test
+    public void onAccessibilityButtonModeChanged_navBarModeAndHasButtonTargets_showWidget() {
+        Settings.Secure.putString(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, TEST_A11Y_BTN_TARGETS);
+        mController = setUpController();
+
+        mController.onAccessibilityButtonModeChanged(ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR);
+
+        assertThat(mController.mFloatingMenu).isNull();
+    }
+
+    @Test
+    public void onAccessibilityButtonModeChanged_navBarModeAndNoButtonTargets_destroyWidget() {
+        Settings.Secure.putString(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, "");
+        mController = setUpController();
+
+        mController.onAccessibilityButtonModeChanged(ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR);
+
+        assertThat(mController.mFloatingMenu).isNull();
+    }
+
+    @Test
+    public void onAccessibilityButtonTargetsChanged_floatingModeAndHasButtonTargets_showWidget() {
+        Settings.Secure.putInt(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU);
+        mController = setUpController();
+
+        mController.onAccessibilityButtonTargetsChanged(TEST_A11Y_BTN_TARGETS);
+
+        assertThat(mController.mFloatingMenu).isNotNull();
+    }
+
+    @Test
+    public void onAccessibilityButtonTargetsChanged_floatingModeAndNoButtonTargets_destroyWidget() {
+        Settings.Secure.putInt(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU);
+        mController = setUpController();
+
+        mController.onAccessibilityButtonTargetsChanged("");
+
+        assertThat(mController.mFloatingMenu).isNull();
+    }
+
+    @Test
+    public void onAccessibilityButtonTargetsChanged_navBarModeAndHasButtonTargets_showWidget() {
+        Settings.Secure.putInt(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
+                ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR);
+        mController = setUpController();
+
+        mController.onAccessibilityButtonTargetsChanged(TEST_A11Y_BTN_TARGETS);
+
+        assertThat(mController.mFloatingMenu).isNull();
+    }
+
+    @Test
+    public void onAccessibilityButtonTargetsChanged_buttonModeAndNoButtonTargets_destroyWidget() {
+        Settings.Secure.putInt(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
+                ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR);
+        mController = setUpController();
+
+        mController.onAccessibilityButtonTargetsChanged("");
+
+        assertThat(mController.mFloatingMenu).isNull();
+    }
+
+    private AccessibilityFloatingMenuController setUpController() {
+        mTargetsObserver = spy(Dependency.get(AccessibilityButtonTargetsObserver.class));
+        mModeObserver = spy(Dependency.get(AccessibilityButtonModeObserver.class));
+        mContext.addMockSystemService(AccessibilityManager.class, mMockA11yManager);
+
+        return new AccessibilityFloatingMenuController(mContext, mTargetsObserver,
+                mModeObserver);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuTest.java
new file mode 100644
index 0000000..337d97e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.floatingmenu;
+
+import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import android.content.Context;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.accessibility.AccessibilityManager;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.accessibility.dialog.AccessibilityTarget;
+import com.android.systemui.SysuiTestCase;
+
+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;
+import java.util.List;
+
+/** Tests for {@link AccessibilityFloatingMenu}. */
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class AccessibilityFloatingMenuTest extends SysuiTestCase {
+
+    @Mock
+    private AccessibilityManager mAccessibilityManager;
+
+    private AccessibilityFloatingMenuView mMenuView;
+    private AccessibilityFloatingMenu mMenu;
+
+    @Before
+    public void initMenu() {
+        MockitoAnnotations.initMocks(this);
+
+        final List<AccessibilityTarget> mTargets = new ArrayList<>();
+        mTargets.add(mock(AccessibilityTarget.class));
+
+        final List<String> assignedTargets = new ArrayList<>();
+        mContext.addMockSystemService(Context.ACCESSIBILITY_SERVICE, mAccessibilityManager);
+        assignedTargets.add(MAGNIFICATION_CONTROLLER_NAME);
+        doReturn(assignedTargets).when(mAccessibilityManager).getAccessibilityShortcutTargets(
+                anyInt());
+
+        mMenuView = new AccessibilityFloatingMenuView(mContext);
+        mMenu = new AccessibilityFloatingMenu(mContext, mMenuView);
+    }
+
+    @Test
+    public void showMenuView_success() {
+        mMenu.show();
+
+        assertThat(mMenuView.isShowing()).isTrue();
+    }
+
+    @Test
+    public void hideMenuView_success() {
+        mMenu.show();
+        mMenu.hide();
+
+        assertThat(mMenuView.isShowing()).isFalse();
+    }
+
+    @After
+    public void tearDown() {
+        mMenu.hide();
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java
new file mode 100644
index 0000000..8683dd6
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.floatingmenu;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.LayerDrawable;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewPropertyAnimator;
+import android.view.WindowManager;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.accessibility.dialog.AccessibilityTarget;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.accessibility.MotionEventHelper;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Tests for {@link AccessibilityFloatingMenuView}. */
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class AccessibilityFloatingMenuViewTest extends SysuiTestCase {
+    private AccessibilityFloatingMenuView mMenuView;
+
+    @Mock
+    private WindowManager mWindowManager;
+
+    @Mock
+    private ViewPropertyAnimator mAnimator;
+
+    private MotionEvent mInterceptMotionEvent;
+
+    private RecyclerView mListView;
+
+    private int mMenuHalfWidth;
+    private int mMenuHalfHeight;
+    private int mScreenHalfWidth;
+    private int mScreenHalfHeight;
+    private int mMaxWindowX;
+
+    private final MotionEventHelper mMotionEventHelper = new MotionEventHelper();
+    private final List<AccessibilityTarget> mTargets = new ArrayList<>();
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        final WindowManager wm = mContext.getSystemService(WindowManager.class);
+        doAnswer(invocation -> wm.getMaximumWindowMetrics()).when(
+                mWindowManager).getMaximumWindowMetrics();
+        mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager);
+
+        mTargets.add(mock(AccessibilityTarget.class));
+        mListView = new RecyclerView(mContext);
+        mMenuView = new AccessibilityFloatingMenuView(mContext, mListView);
+
+        final Resources res = mContext.getResources();
+        final int margin =
+                res.getDimensionPixelSize(R.dimen.accessibility_floating_menu_margin);
+        final int padding =
+                res.getDimensionPixelSize(R.dimen.accessibility_floating_menu_padding);
+        final int iconWidthHeight =
+                res.getDimensionPixelSize(R.dimen.accessibility_floating_menu_small_width_height);
+        final int menuWidth = padding * 2 + iconWidthHeight;
+        final int menuHeight = (padding + iconWidthHeight) * mTargets.size() + padding;
+        final int screenWidth = mContext.getResources().getDisplayMetrics().widthPixels;
+        final int screenHeight = mContext.getResources().getDisplayMetrics().heightPixels;
+        mMenuHalfWidth = menuWidth / 2;
+        mMenuHalfHeight = menuHeight / 2;
+        mScreenHalfWidth = screenWidth / 2;
+        mScreenHalfHeight = screenHeight / 2;
+        mMaxWindowX = screenWidth - margin - menuWidth;
+    }
+
+    @Test
+    public void initListView_success() {
+        assertThat(mMenuView.getChildCount()).isEqualTo(1);
+    }
+
+    @Test
+    public void showMenuView_success() {
+        mMenuView.show();
+
+        assertThat(mMenuView.isShowing()).isTrue();
+        verify(mWindowManager).addView(eq(mMenuView), any(WindowManager.LayoutParams.class));
+    }
+
+    @Test
+    public void showMenuView_showTwice_addViewOnce() {
+        mMenuView.show();
+        mMenuView.show();
+
+        assertThat(mMenuView.isShowing()).isTrue();
+        verify(mWindowManager, times(1)).addView(eq(mMenuView),
+                any(WindowManager.LayoutParams.class));
+    }
+
+    @Test
+    public void hideMenuView_success() {
+        mMenuView.show();
+        mMenuView.hide();
+
+        assertThat(mMenuView.isShowing()).isFalse();
+        verify(mWindowManager).removeView(eq(mMenuView));
+    }
+
+    @Test
+    public void hideMenuView_hideTwice_removeViewOnce() {
+        mMenuView.show();
+        mMenuView.hide();
+        mMenuView.hide();
+
+        assertThat(mMenuView.isShowing()).isFalse();
+        verify(mWindowManager, times(1)).removeView(eq(mMenuView));
+    }
+
+    @Test
+    public void updateListViewRadius_singleTarget_matchResult() {
+        final float radius =
+                getContext().getResources().getDimensionPixelSize(
+                        R.dimen.accessibility_floating_menu_small_single_radius);
+        final float[] expectedRadii =
+                new float[]{radius, radius, 0.0f, 0.0f, 0.0f, 0.0f, radius, radius};
+
+        mMenuView.onTargetsChanged(mTargets);
+        final View view = mMenuView.getChildAt(0);
+        final LayerDrawable layerDrawable = (LayerDrawable) view.getBackground();
+        final GradientDrawable gradientDrawable =
+                (GradientDrawable) layerDrawable.getDrawable(0);
+        final float[] actualRadii = gradientDrawable.getCornerRadii();
+
+        assertThat(actualRadii).isEqualTo(expectedRadii);
+    }
+
+    @Test
+    public void setSizeType_largeSize_matchResult() {
+        final int shapeType = 2;
+        final float radius = getContext().getResources().getDimensionPixelSize(
+                R.dimen.accessibility_floating_menu_large_single_radius);
+        final float[] expectedRadii =
+                new float[]{radius, radius, 0.0f, 0.0f, 0.0f, 0.0f, radius, radius};
+        final Drawable listViewBackground =
+                mContext.getDrawable(R.drawable.accessibility_floating_menu_background);
+        mListView = spy(new RecyclerView(mContext));
+        mListView.setBackground(listViewBackground);
+
+        mMenuView = new AccessibilityFloatingMenuView(mContext, mListView);
+        mMenuView.setSizeType(shapeType);
+        final LayerDrawable layerDrawable =
+                (LayerDrawable) mListView.getBackground();
+        final GradientDrawable gradientDrawable =
+                (GradientDrawable) layerDrawable.getDrawable(0);
+
+        assertThat(gradientDrawable.getCornerRadii()).isEqualTo(expectedRadii);
+    }
+
+    @Test
+    public void setShapeType_halfCircle_translationX() {
+        final RecyclerView listView = spy(new RecyclerView(mContext));
+        final AccessibilityFloatingMenuView menuView =
+                new AccessibilityFloatingMenuView(mContext, listView);
+        final int shapeType = 2;
+        doReturn(mAnimator).when(listView).animate();
+
+        menuView.setShapeType(shapeType);
+
+        verify(mAnimator).translationX(anyFloat());
+    }
+
+    @Test
+    public void onTargetsChanged_fadeInOut() {
+        final AccessibilityFloatingMenuView menuView = spy(mMenuView);
+        final InOrder inOrderMenuView = inOrder(menuView);
+
+        menuView.onTargetsChanged(mTargets);
+
+        inOrderMenuView.verify(menuView).fadeIn();
+        inOrderMenuView.verify(menuView).fadeOut();
+    }
+
+    @Test
+    public void setSizeType_fadeInOut() {
+        final AccessibilityFloatingMenuView menuView = spy(mMenuView);
+        final InOrder inOrderMenuView = inOrder(menuView);
+        final int smallSize = 0;
+        menuView.setSizeType(smallSize);
+
+        inOrderMenuView.verify(menuView).fadeIn();
+        inOrderMenuView.verify(menuView).fadeOut();
+    }
+
+    @Test
+    public void tapOnAndDragMenu_interceptUpEvent() {
+        final RecyclerView listView = new RecyclerView(mContext);
+        final TestAccessibilityFloatingMenu menuView =
+                new TestAccessibilityFloatingMenu(mContext, listView);
+
+        menuView.show();
+        menuView.onTargetsChanged(mTargets);
+        menuView.setSizeType(0);
+        menuView.setShapeType(0);
+        final int currentWindowX = mMenuView.mCurrentLayoutParams.x;
+        final int currentWindowY = mMenuView.mCurrentLayoutParams.y;
+        final MotionEvent downEvent =
+                mMotionEventHelper.obtainMotionEvent(0, 1,
+                        MotionEvent.ACTION_DOWN,
+                        currentWindowX + /* offsetXToMenuCenterX */ mMenuHalfWidth,
+                        currentWindowY + /* offsetYToMenuCenterY */ mMenuHalfHeight);
+        final MotionEvent moveEvent =
+                mMotionEventHelper.obtainMotionEvent(2, 3,
+                        MotionEvent.ACTION_MOVE,
+                        /* screenCenterX */mScreenHalfWidth
+                                - /* offsetXToScreenLeftHalfRegion */ 10,
+                        /* screenCenterY */ mScreenHalfHeight);
+        final MotionEvent upEvent =
+                mMotionEventHelper.obtainMotionEvent(4, 5,
+                        MotionEvent.ACTION_UP,
+                        /* screenCenterX */ mScreenHalfWidth
+                                - /* offsetXToScreenLeftHalfRegion */ 10,
+                        /* screenCenterY */ mScreenHalfHeight);
+        listView.dispatchTouchEvent(downEvent);
+        listView.dispatchTouchEvent(moveEvent);
+        listView.dispatchTouchEvent(upEvent);
+
+        assertThat(mInterceptMotionEvent.getAction()).isEqualTo(MotionEvent.ACTION_UP);
+    }
+
+    @Test
+    public void tapOnAndDragMenu_matchLocation() {
+        mMenuView.show();
+        mMenuView.onTargetsChanged(mTargets);
+        mMenuView.setSizeType(0);
+        mMenuView.setShapeType(0);
+        final int currentWindowX = mMenuView.mCurrentLayoutParams.x;
+        final int currentWindowY = mMenuView.mCurrentLayoutParams.y;
+        final MotionEvent downEvent =
+                mMotionEventHelper.obtainMotionEvent(0, 1,
+                        MotionEvent.ACTION_DOWN,
+                        currentWindowX + /* offsetXToMenuCenterX */ mMenuHalfWidth,
+                        currentWindowY + /* offsetYToMenuCenterY */ mMenuHalfHeight);
+        final MotionEvent moveEvent =
+                mMotionEventHelper.obtainMotionEvent(2, 3,
+                        MotionEvent.ACTION_MOVE,
+                        /* screenCenterX */mScreenHalfWidth
+                                + /* offsetXToScreenRightHalfRegion */ 10,
+                        /* screenCenterY */ mScreenHalfHeight);
+        final MotionEvent upEvent =
+                mMotionEventHelper.obtainMotionEvent(4, 5,
+                        MotionEvent.ACTION_UP,
+                        /* screenCenterX */ mScreenHalfWidth
+                                + /* offsetXToScreenRightHalfRegion */ 10,
+                        /* screenCenterY */ mScreenHalfHeight);
+        mListView.dispatchTouchEvent(downEvent);
+        mListView.dispatchTouchEvent(moveEvent);
+        mListView.dispatchTouchEvent(upEvent);
+        mMenuView.mDragAnimator.end();
+
+        assertThat(mMenuView.mCurrentLayoutParams.x).isEqualTo(mMaxWindowX);
+        assertThat(mMenuView.mCurrentLayoutParams.y).isEqualTo(
+                /* newWindowY = screenCenterY - offsetY */ mScreenHalfHeight - mMenuHalfHeight);
+    }
+
+
+    @Test
+    public void tapOnAndDragMenuToScreenSide_transformShapeHalfOval() {
+        mMenuView.show();
+        mMenuView.onTargetsChanged(mTargets);
+        mMenuView.setSizeType(0);
+        mMenuView.setShapeType(/* oval */ 0);
+        final int currentWindowX = mMenuView.mCurrentLayoutParams.x;
+        final int currentWindowY = mMenuView.mCurrentLayoutParams.y;
+        final MotionEvent downEvent =
+                mMotionEventHelper.obtainMotionEvent(0, 1,
+                        MotionEvent.ACTION_DOWN,
+                        currentWindowX + /* offsetXToMenuCenterX */ mMenuHalfWidth,
+                        currentWindowY + /* offsetYToMenuCenterY */ mMenuHalfHeight);
+        final MotionEvent moveEvent =
+                mMotionEventHelper.obtainMotionEvent(2, 3,
+                        MotionEvent.ACTION_MOVE,
+                        /* downX */(currentWindowX + mMenuHalfWidth)
+                                + /* offsetXToScreenRightSide */ mMenuHalfWidth,
+                        /* downY */ (currentWindowY +  mMenuHalfHeight));
+        final MotionEvent upEvent =
+                mMotionEventHelper.obtainMotionEvent(4, 5,
+                        MotionEvent.ACTION_UP,
+                        /* downX */(currentWindowX + mMenuHalfWidth)
+                                + /* offsetXToScreenRightSide */ mMenuHalfWidth,
+                        /* downY */ (currentWindowY +  mMenuHalfHeight));
+        mListView.dispatchTouchEvent(downEvent);
+        mListView.dispatchTouchEvent(moveEvent);
+        mListView.dispatchTouchEvent(upEvent);
+
+        assertThat(mMenuView.mShapeType).isEqualTo(/* halfOval */ 1);
+    }
+
+    @After
+    public void tearDown() {
+        mInterceptMotionEvent = null;
+        mMotionEventHelper.recycleEvents();
+    }
+
+    private class TestAccessibilityFloatingMenu extends AccessibilityFloatingMenuView {
+        TestAccessibilityFloatingMenu(Context context, RecyclerView listView) {
+            super(context, listView);
+        }
+
+        @Override
+        public boolean onInterceptTouchEvent(@NonNull RecyclerView recyclerView,
+                @NonNull MotionEvent event) {
+            final boolean intercept = super.onInterceptTouchEvent(recyclerView, event);
+
+            if (intercept) {
+                mInterceptMotionEvent = event;
+            }
+
+            return intercept;
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityTargetAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityTargetAdapterTest.java
new file mode 100644
index 0000000..899625e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityTargetAdapterTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.floatingmenu;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.graphics.drawable.Drawable;
+import android.testing.AndroidTestingRunner;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.accessibility.dialog.AccessibilityTarget;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.accessibility.floatingmenu.AccessibilityTargetAdapter.ViewHolder;
+
+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;
+import java.util.List;
+
+/** Tests for {@link AccessibilityTargetAdapter}. */
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class AccessibilityTargetAdapterTest extends SysuiTestCase {
+    @Mock
+    private AccessibilityTarget mAccessibilityTarget;
+
+    @Mock
+    private Drawable mIcon;
+
+    @Mock
+    private Drawable.ConstantState mConstantState;
+
+    private ViewHolder mViewHolder;
+    private AccessibilityTargetAdapter mAdapter;
+    private final List<AccessibilityTarget> mTargets = new ArrayList<>();
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mTargets.add(mAccessibilityTarget);
+        mAdapter = new AccessibilityTargetAdapter(mTargets);
+
+        final View root = LayoutInflater.from(mContext).inflate(
+                R.layout.accessibility_floating_menu_item, null);
+        mViewHolder = new ViewHolder(root);
+        when(mAccessibilityTarget.getIcon()).thenReturn(mIcon);
+        when(mIcon.getConstantState()).thenReturn(mConstantState);
+    }
+
+    @Test
+    public void onBindViewHolder_setIconWidthHeight_matchResult() {
+        final int iconWidthHeight = 50;
+        mAdapter.setIconWidthHeight(iconWidthHeight);
+
+        mAdapter.onBindViewHolder(mViewHolder, 0);
+        final int actualIconWith = mViewHolder.mIconView.getLayoutParams().width;
+
+        assertThat(actualIconWith).isEqualTo(iconWidthHeight);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
index 7f8be91..1565dee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
@@ -26,6 +26,7 @@
 import static org.mockito.Mockito.verify;
 
 import android.content.Context;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.PromptInfo;
 import android.hardware.biometrics.SensorProperties;
 import android.hardware.fingerprint.FingerprintSensorProperties;
@@ -49,6 +50,9 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.ArrayList;
+import java.util.List;
+
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
 @SmallTest
@@ -341,8 +345,18 @@
         final int sensorLocationX = 540;
         final int sensorLocationY = 1600;
         final int sensorRadius = 100;
+
+        final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
+        componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */,
+                "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */,
+                "00000001" /* serialNumber */, "" /* softwareVersion */));
+        componentInfo.add(new ComponentInfoInternal("matchingAlgorithm" /* componentId */,
+                "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */,
+                "vendor/version/revision" /* softwareVersion */));
+
         final FingerprintSensorPropertiesInternal props = new FingerprintSensorPropertiesInternal(
                 0 /* sensorId */, SensorProperties.STRENGTH_STRONG, 5 /* maxEnrollmentsPerUser */,
+                componentInfo,
                 FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
                 true /* resetLockoutRequiresHardwareAuthToken */, sensorLocationX, sensorLocationY,
                 sensorRadius);
@@ -379,8 +393,18 @@
         final int sensorLocationX = 540;
         final int sensorLocationY = 1600;
         final int sensorRadius = 100;
+
+        final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
+        componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */,
+                "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */,
+                "00000001" /* serialNumber */, "" /* softwareVersion */));
+        componentInfo.add(new ComponentInfoInternal("matchingAlgorithm" /* componentId */,
+                "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */,
+                "vendor/version/revision" /* softwareVersion */));
+
         final FingerprintSensorPropertiesInternal props = new FingerprintSensorPropertiesInternal(
                 0 /* sensorId */, SensorProperties.STRENGTH_STRONG, 5 /* maxEnrollmentsPerUser */,
+                componentInfo,
                 FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
                 true /* resetLockoutRequiresHardwareAuthToken */, sensorLocationX, sensorLocationY,
                 sensorRadius);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java
index 5088a53..f41c100 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java
@@ -34,8 +34,8 @@
 
 import android.annotation.Nullable;
 import android.content.Context;
-import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.PromptInfo;
 import android.hardware.biometrics.SensorProperties;
 import android.hardware.face.FaceSensorPropertiesInternal;
@@ -248,9 +248,19 @@
         config.mPromptInfo = promptInfo;
 
         final List<FingerprintSensorPropertiesInternal> fpProps = new ArrayList<>();
+
+        final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
+        componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */,
+                "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */,
+                "00000001" /* serialNumber */, "" /* softwareVersion */));
+        componentInfo.add(new ComponentInfoInternal("matchingAlgorithm" /* componentId */,
+                "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */,
+                "vendor/version/revision" /* softwareVersion */));
+
         fpProps.add(new FingerprintSensorPropertiesInternal(0,
                 SensorProperties.STRENGTH_STRONG,
                 5 /* maxEnrollmentsPerUser */,
+                componentInfo,
                 FingerprintSensorProperties.TYPE_REAR,
                 false /* resetLockoutRequiresHardwareAuthToken */));
         mAuthContainer = new TestableAuthContainer(config, fpProps, null /* faceProps */);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index 30c4cf6..fa190a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -34,7 +34,6 @@
 
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
-import android.app.IActivityTaskManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -43,6 +42,7 @@
 import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.BiometricConstants;
 import android.hardware.biometrics.BiometricPrompt;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.IBiometricSysuiReceiver;
 import android.hardware.biometrics.PromptInfo;
 import android.hardware.biometrics.SensorProperties;
@@ -123,10 +123,20 @@
         when(mDialog2.isAllowDeviceCredentials()).thenReturn(false);
 
         when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+
+        final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
+        componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */,
+                "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */,
+                "00000001" /* serialNumber */, "" /* softwareVersion */));
+        componentInfo.add(new ComponentInfoInternal("matchingAlgorithm" /* componentId */,
+                "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */,
+                "vendor/version/revision" /* softwareVersion */));
+
         FingerprintSensorPropertiesInternal prop = new FingerprintSensorPropertiesInternal(
                 1 /* sensorId */,
                 SensorProperties.STRENGTH_STRONG,
                 1 /* maxEnrollmentsPerUser */,
+                componentInfo,
                 FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
                 true /* resetLockoutRequireHardwareAuthToken */);
         List<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
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 be110fc..3f1a927 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -26,6 +26,7 @@
 
 import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.SensorProperties;
 import android.hardware.fingerprint.FingerprintManager;
 import android.hardware.fingerprint.FingerprintSensorProperties;
@@ -120,9 +121,19 @@
         setUpResources();
         when(mLayoutInflater.inflate(R.layout.udfps_view, null, false)).thenReturn(mUdfpsView);
         final List<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
+
+        final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
+        componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */,
+                "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */,
+                "00000001" /* serialNumber */, "" /* softwareVersion */));
+        componentInfo.add(new ComponentInfoInternal("matchingAlgorithm" /* componentId */,
+                "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */,
+                "vendor/version/revision" /* softwareVersion */));
+
         props.add(new FingerprintSensorPropertiesInternal(TEST_UDFPS_SENSOR_ID,
                 SensorProperties.STRENGTH_STRONG,
                 5 /* maxEnrollmentsPerUser */,
+                componentInfo,
                 FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
                 true /* resetLockoutRequiresHardwareAuthToken */));
         when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(props);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
index d015f51..67c1d07 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
@@ -21,6 +21,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyCollection;
 import static org.mockito.ArgumentMatchers.anyDouble;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -78,17 +79,21 @@
 
     private final FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
 
-    private final FalsingClassifier.Result mFalsedResult = FalsingClassifier.Result.falsed(1, "");
+    private final FalsingClassifier.Result mFalsedResult =
+            FalsingClassifier.Result.falsed(1, getClass().getSimpleName(), "");
     private final FalsingClassifier.Result mPassedResult = FalsingClassifier.Result.passed(1);
     private GestureCompleteListener mGestureCompleteListener;
 
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
-        when(mClassifierA.classifyGesture(anyDouble(), anyDouble())).thenReturn(mPassedResult);
-        when(mClassifierB.classifyGesture(anyDouble(), anyDouble())).thenReturn(mPassedResult);
+        when(mClassifierA.classifyGesture(anyInt(), anyDouble(), anyDouble()))
+                .thenReturn(mPassedResult);
+        when(mClassifierB.classifyGesture(anyInt(), anyDouble(), anyDouble()))
+                .thenReturn(mPassedResult);
         when(mSingleTapClassfier.isTap(any(List.class))).thenReturn(mPassedResult);
-        when(mDoubleTapClassifier.classifyGesture()).thenReturn(mPassedResult);
+        when(mDoubleTapClassifier.classifyGesture(anyInt(), anyDouble(), anyDouble()))
+                .thenReturn(mPassedResult);
         mClassifiers.add(mClassifierA);
         mClassifiers.add(mClassifierB);
         when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(mMotionEventList);
@@ -131,20 +136,23 @@
 
     @Test
     public void testIsFalseTouch_ClassifierARejects() {
-        when(mClassifierA.classifyGesture(anyDouble(), anyDouble())).thenReturn(mFalsedResult);
+        when(mClassifierA.classifyGesture(anyInt(), anyDouble(), anyDouble()))
+                .thenReturn(mFalsedResult);
         assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isTrue();
     }
 
     @Test
     public void testIsFalseTouch_ClassifierBRejects() {
-        when(mClassifierB.classifyGesture(anyDouble(), anyDouble())).thenReturn(mFalsedResult);
+        when(mClassifierB.classifyGesture(anyInt(), anyDouble(), anyDouble()))
+                .thenReturn(mFalsedResult);
         assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isTrue();
     }
 
     @Test
     public void testIsFalseTouch_FaceAuth() {
         // Even when the classifiers report a false, we should allow.
-        when(mClassifierA.classifyGesture(anyDouble(), anyDouble())).thenReturn(mPassedResult);
+        when(mClassifierA.classifyGesture(anyInt(), anyDouble(), anyDouble()))
+                .thenReturn(mPassedResult);
         when(mFalsingDataProvider.isJustUnlockedWithFace()).thenReturn(true);
 
         assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isFalse();
@@ -153,7 +161,8 @@
     @Test
     public void testIsFalseTouch_Docked() {
         // Even when the classifiers report a false, we should allow.
-        when(mClassifierA.classifyGesture(anyDouble(), anyDouble())).thenReturn(mPassedResult);
+        when(mClassifierA.classifyGesture(anyInt(), anyDouble(), anyDouble()))
+                .thenReturn(mPassedResult);
         mDockManager.setIsDocked(true);
 
         assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isFalse();
@@ -173,7 +182,8 @@
     @Test
     public void testIsFalseTap_RobustCheck_NoFaceAuth() {
         when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(mPassedResult);
-        when(mDoubleTapClassifier.classifyGesture()).thenReturn(mFalsedResult);
+        when(mDoubleTapClassifier.classifyGesture(anyInt(), anyDouble(), anyDouble()))
+                .thenReturn(mFalsedResult);
         when(mHistoryTracker.falseBelief()).thenReturn(1.0);
         mFalsingDataProvider.setJustUnlockedWithFace(false);
         assertThat(mBrightLineFalsingManager.isFalseTap(true, 0)).isTrue();
@@ -188,11 +198,13 @@
 
     @Test
     public void testIsFalseDoubleTap() {
-        when(mDoubleTapClassifier.classifyGesture()).thenReturn(mPassedResult);
+        when(mDoubleTapClassifier.classifyGesture(anyInt(), anyDouble(), anyDouble()))
+                .thenReturn(mPassedResult);
 
         assertThat(mBrightLineFalsingManager.isFalseDoubleTap()).isFalse();
 
-        when(mDoubleTapClassifier.classifyGesture()).thenReturn(mFalsedResult);
+        when(mDoubleTapClassifier.classifyGesture(anyInt(), anyDouble(), anyDouble()))
+                .thenReturn(mFalsedResult);
 
         assertThat(mBrightLineFalsingManager.isFalseDoubleTap()).isTrue();
     }
@@ -243,13 +255,15 @@
     public void testNoFalsingUnlocked() {
         when(mKeyguardStateController.isShowing()).thenReturn(false);
 
-        when(mClassifierA.classifyGesture(anyDouble(), anyDouble())).thenReturn(mFalsedResult);
+        when(mClassifierA.classifyGesture(anyInt(), anyDouble(), anyDouble()))
+                .thenReturn(mFalsedResult);
         assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isFalse();
 
         when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(mFalsedResult);
         assertThat(mBrightLineFalsingManager.isFalseTap(false, 0)).isFalse();
 
-        when(mDoubleTapClassifier.classifyGesture()).thenReturn(mFalsedResult);
+        when(mDoubleTapClassifier.classifyGesture(anyInt(), anyDouble(), anyDouble()))
+                .thenReturn(mFalsedResult);
         assertThat(mBrightLineFalsingManager.isFalseDoubleTap()).isFalse();
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java
index ca0a4aa..7d6ff34 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.classifier;
 
-import static com.android.systemui.classifier.Classifier.UNLOCK;
-
 import android.util.DisplayMetrics;
 import android.view.MotionEvent;
 
@@ -45,7 +43,6 @@
         displayMetrics.heightPixels = 1000;
         mFakeBatteryController = new FakeBatteryController(getLeakCheck());
         mDataProvider = new FalsingDataProvider(displayMetrics, mFakeBatteryController);
-        mDataProvider.setInteractionType(UNLOCK);
     }
 
     @After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/DiagonalClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/DiagonalClassifierTest.java
index dafc871..14dcd58 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/DiagonalClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/DiagonalClassifierTest.java
@@ -16,11 +16,12 @@
 
 package com.android.systemui.classifier;
 
+import static com.android.systemui.classifier.Classifier.GENERIC;
 import static com.android.systemui.classifier.Classifier.LEFT_AFFORDANCE;
 import static com.android.systemui.classifier.Classifier.RIGHT_AFFORDANCE;
 
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.Mockito.when;
 
 import android.testing.AndroidTestingRunner;
@@ -69,106 +70,104 @@
     @Test
     public void testPass_UnknownAngle() {
         when(mDataProvider.getAngle()).thenReturn(Float.MAX_VALUE);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isFalse();
     }
 
     @Test
     public void testPass_VerticalSwipe() {
         when(mDataProvider.getAngle()).thenReturn(UP_IN_RADIANS);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isFalse();
 
         when(mDataProvider.getAngle()).thenReturn(DOWN_IN_RADIANS);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isFalse();
     }
 
     @Test
     public void testPass_MostlyVerticalSwipe() {
         when(mDataProvider.getAngle()).thenReturn(UP_IN_RADIANS + 2 * FIVE_DEG_IN_RADIANS);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isFalse();
 
         when(mDataProvider.getAngle()).thenReturn(UP_IN_RADIANS - 2 * FIVE_DEG_IN_RADIANS);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isFalse();
 
         when(mDataProvider.getAngle()).thenReturn(DOWN_IN_RADIANS + 2 * FIVE_DEG_IN_RADIANS);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isFalse();
 
         when(mDataProvider.getAngle()).thenReturn(DOWN_IN_RADIANS - 2 * FIVE_DEG_IN_RADIANS * 2);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isFalse();
     }
 
     @Test
     public void testPass_BarelyVerticalSwipe() {
         when(mDataProvider.getAngle()).thenReturn(
                 UP_IN_RADIANS - FORTY_FIVE_DEG_IN_RADIANS + 2 * FIVE_DEG_IN_RADIANS);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isFalse();
 
         when(mDataProvider.getAngle()).thenReturn(
                 UP_IN_RADIANS + FORTY_FIVE_DEG_IN_RADIANS - 2 * FIVE_DEG_IN_RADIANS);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isFalse();
 
         when(mDataProvider.getAngle()).thenReturn(
                 DOWN_IN_RADIANS - FORTY_FIVE_DEG_IN_RADIANS + 2 * FIVE_DEG_IN_RADIANS);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isFalse();
 
         when(mDataProvider.getAngle()).thenReturn(
                 DOWN_IN_RADIANS + FORTY_FIVE_DEG_IN_RADIANS - 2 * FIVE_DEG_IN_RADIANS * 2);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isFalse();
     }
 
     @Test
     public void testPass_HorizontalSwipe() {
         when(mDataProvider.getAngle()).thenReturn(RIGHT_IN_RADIANS);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isFalse();
 
         when(mDataProvider.getAngle()).thenReturn(LEFT_IN_RADIANS);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isFalse();
     }
 
     @Test
     public void testPass_MostlyHorizontalSwipe() {
         when(mDataProvider.getAngle()).thenReturn(RIGHT_IN_RADIANS + 2 * FIVE_DEG_IN_RADIANS);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isFalse();
 
         when(mDataProvider.getAngle()).thenReturn(RIGHT_IN_RADIANS - 2 * FIVE_DEG_IN_RADIANS);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isFalse();
 
         when(mDataProvider.getAngle()).thenReturn(LEFT_IN_RADIANS + 2 * FIVE_DEG_IN_RADIANS);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isFalse();
 
         when(mDataProvider.getAngle()).thenReturn(LEFT_IN_RADIANS - 2 * FIVE_DEG_IN_RADIANS);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isFalse();
     }
 
     @Test
     public void testPass_BarelyHorizontalSwipe() {
         when(mDataProvider.getAngle()).thenReturn(
                 RIGHT_IN_RADIANS + FORTY_FIVE_DEG_IN_RADIANS - 2 * FIVE_DEG_IN_RADIANS);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isFalse();
 
         when(mDataProvider.getAngle()).thenReturn(
                 LEFT_IN_RADIANS - FORTY_FIVE_DEG_IN_RADIANS + 2 * FIVE_DEG_IN_RADIANS);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isFalse();
 
         when(mDataProvider.getAngle()).thenReturn(
                 LEFT_IN_RADIANS + FORTY_FIVE_DEG_IN_RADIANS - 2 * FIVE_DEG_IN_RADIANS);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isFalse();
 
         when(mDataProvider.getAngle()).thenReturn(
                 RIGHT_IN_RADIANS - FORTY_FIVE_DEG_IN_RADIANS + 2 * FIVE_DEG_IN_RADIANS * 2);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isFalse();
     }
 
     @Test
     public void testPass_AffordanceSwipe() {
-        when(mDataProvider.getInteractionType()).thenReturn(LEFT_AFFORDANCE);
         when(mDataProvider.getAngle()).thenReturn(
                 RIGHT_IN_RADIANS + FORTY_FIVE_DEG_IN_RADIANS);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(LEFT_AFFORDANCE, 0.5, 0).isFalse()).isFalse();
 
-        when(mDataProvider.getInteractionType()).thenReturn(RIGHT_AFFORDANCE);
         when(mDataProvider.getAngle()).thenReturn(
                 LEFT_IN_RADIANS - FORTY_FIVE_DEG_IN_RADIANS);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(RIGHT_AFFORDANCE, 0.5, 0).isFalse()).isFalse();
 
         // This classifier may return false for other angles, but these are the only
         // two that actually matter, as affordances generally only travel in these two directions.
@@ -182,37 +181,37 @@
         when(mDataProvider.isVertical()).thenReturn(false);
         when(mDataProvider.getAngle()).thenReturn(
                 RIGHT_IN_RADIANS + FORTY_FIVE_DEG_IN_RADIANS - FIVE_DEG_IN_RADIANS);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isTrue();
 
         when(mDataProvider.getAngle()).thenReturn(
                 UP_IN_RADIANS + FORTY_FIVE_DEG_IN_RADIANS + FIVE_DEG_IN_RADIANS);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isTrue();
 
         when(mDataProvider.getAngle()).thenReturn(
                 LEFT_IN_RADIANS + FORTY_FIVE_DEG_IN_RADIANS - FIVE_DEG_IN_RADIANS);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isTrue();
 
         when(mDataProvider.getAngle()).thenReturn(
                 DOWN_IN_RADIANS + FORTY_FIVE_DEG_IN_RADIANS + FIVE_DEG_IN_RADIANS);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isTrue();
 
         // Vertical Swipes
         when(mDataProvider.isVertical()).thenReturn(true);
         when(mDataProvider.getAngle()).thenReturn(
                 RIGHT_IN_RADIANS + FORTY_FIVE_DEG_IN_RADIANS + FIVE_DEG_IN_RADIANS);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isTrue();
 
         when(mDataProvider.getAngle()).thenReturn(
                 UP_IN_RADIANS + FORTY_FIVE_DEG_IN_RADIANS - FIVE_DEG_IN_RADIANS);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isTrue();
 
 
         when(mDataProvider.getAngle()).thenReturn(
                 LEFT_IN_RADIANS + FORTY_FIVE_DEG_IN_RADIANS + FIVE_DEG_IN_RADIANS);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isTrue();
 
         when(mDataProvider.getAngle()).thenReturn(
                 DOWN_IN_RADIANS + FORTY_FIVE_DEG_IN_RADIANS - FIVE_DEG_IN_RADIANS);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse()).isTrue();
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java
index f6c1424..db06199 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java
@@ -16,8 +16,7 @@
 
 package com.android.systemui.classifier;
 
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
+import static com.google.common.truth.Truth.assertThat;
 
 import android.testing.AndroidTestingRunner;
 
@@ -51,32 +50,32 @@
 
     @Test
     public void testPass_noPointer() {
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
     }
 
     @Test
     public void testPass_fling() {
 
         mClassifier.onTouchEvent(appendDownEvent(1, 1));
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
 
         mClassifier.onTouchEvent(appendMoveEvent(1, 40));
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
 
         mClassifier.onTouchEvent(appendUpEvent(1, 80));
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
     }
 
     @Test
     public void testFail_flingShort() {
         mClassifier.onTouchEvent(appendDownEvent(1, 1));
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
 
         mClassifier.onTouchEvent(appendMoveEvent(1, 2));
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
 
         mClassifier.onTouchEvent(appendUpEvent(1, 10));
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
     }
 
     @Test
@@ -84,26 +83,26 @@
         // These events, in testing, result in a fling that falls just short of the threshold.
 
         mClassifier.onTouchEvent(appendDownEvent(1, 1, 1));
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
 
         mClassifier.onTouchEvent(appendMoveEvent(1, 15, 2));
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
 
         mClassifier.onTouchEvent(appendMoveEvent(1, 16, 3));
         mClassifier.onTouchEvent(appendMoveEvent(1, 17, 300));
         mClassifier.onTouchEvent(appendMoveEvent(1, 18, 301));
         mClassifier.onTouchEvent(appendUpEvent(1, 19, 501));
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
     }
 
     @Test
     public void testPass_swipe() {
 
         mClassifier.onTouchEvent(appendDownEvent(1, 1));
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
 
         mClassifier.onTouchEvent(appendMoveEvent(1, mDataProvider.getYdpi() * 3, 3));
         mClassifier.onTouchEvent(appendUpEvent(1, mDataProvider.getYdpi() * 3, 300));
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/DoubleTapClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/DoubleTapClassifierTest.java
index 4e17424..f726cbe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/DoubleTapClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/DoubleTapClassifierTest.java
@@ -16,8 +16,8 @@
 
 package com.android.systemui.classifier;
 
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.ArgumentMatchers.anyList;
 import static org.mockito.Mockito.when;
 
@@ -52,7 +52,8 @@
     private SingleTapClassifier mSingleTapClassifier;
     private DoubleTapClassifier mClassifier;
 
-    private final FalsingClassifier.Result mFalsedResult = FalsingClassifier.Result.falsed(1, "");
+    private final FalsingClassifier.Result mFalsedResult =
+            FalsingClassifier.Result.falsed(1, getClass().getSimpleName(), "");
     private final FalsingClassifier.Result mPassedResult = FalsingClassifier.Result.passed(1);
 
     @Before
@@ -81,8 +82,8 @@
         addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1);
         addMotionEvent(0, 1, MotionEvent.ACTION_UP, TOUCH_SLOP, 1);
 
-        boolean result = mClassifier.classifyGesture().isFalse();
-        assertThat("Single tap recognized as a valid double tap", result,  is(true));
+        boolean result = mClassifier.classifyGesture(0, 0.5, 1).isFalse();
+        assertThat(result).isTrue();
     }
 
     @Test
@@ -97,8 +98,8 @@
         addMotionEvent(2, 2, MotionEvent.ACTION_DOWN, TOUCH_SLOP, TOUCH_SLOP);
         addMotionEvent(2, 3, MotionEvent.ACTION_UP, TOUCH_SLOP, TOUCH_SLOP);
 
-        FalsingClassifier.Result result = mClassifier.classifyGesture();
-        assertThat(result.getReason(), result.isFalse(), is(false));
+        FalsingClassifier.Result result = mClassifier.classifyGesture(0, 0.5, 1);
+        assertThat(result.isFalse()).isFalse();
     }
 
     @Test
@@ -113,8 +114,8 @@
         addMotionEvent(2, 2, MotionEvent.ACTION_DOWN, 1, 1);
         addMotionEvent(2, 3, MotionEvent.ACTION_UP, 1, 1);
 
-        boolean result = mClassifier.classifyGesture().isFalse();
-        assertThat("Bad first touch allowed", result, is(true));
+        boolean result = mClassifier.classifyGesture(0, 0.5, 1).isFalse();
+        assertThat(result).isTrue();
     }
 
     @Test
@@ -129,8 +130,8 @@
         addMotionEvent(2, 2, MotionEvent.ACTION_DOWN, 1, 1);
         addMotionEvent(2, 3, MotionEvent.ACTION_UP, 1, 1);
 
-        boolean result = mClassifier.classifyGesture().isFalse();
-        assertThat("Bad second touch allowed", result, is(true));
+        boolean result = mClassifier.classifyGesture(0, 0.5, 1).isFalse();
+        assertThat(result).isTrue();
     }
 
     @Test
@@ -145,8 +146,8 @@
         addMotionEvent(2, 2, MotionEvent.ACTION_DOWN, TOUCH_SLOP + 1, TOUCH_SLOP);
         addMotionEvent(2, 3, MotionEvent.ACTION_UP, TOUCH_SLOP, TOUCH_SLOP + 1);
 
-        boolean result = mClassifier.classifyGesture().isFalse();
-        assertThat("Sloppy second touch allowed", result, is(true));
+        boolean result = mClassifier.classifyGesture(0, 0.5, 1).isFalse();
+        assertThat(result).isTrue();
     }
 
     @Test
@@ -163,8 +164,8 @@
         addMotionEvent(DOUBLE_TAP_TIMEOUT_MS + 1, DOUBLE_TAP_TIMEOUT_MS + 2,
                 MotionEvent.ACTION_UP, 1, 1);
 
-        boolean result = mClassifier.classifyGesture().isFalse();
-        assertThat("Slow second tap allowed", result, is(true));
+        boolean result = mClassifier.classifyGesture(0, 0.5, 1).isFalse();
+        assertThat(result).isTrue();
     }
 
     private void addMotionEvent(long downMs, long eventMs, int action, int x, int y) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/HistoryTrackerTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/HistoryTrackerTest.java
index bb7545f..38355c7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/HistoryTrackerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/HistoryTrackerTest.java
@@ -121,7 +121,8 @@
     private void addResult(boolean falsed, double confidence) {
         mHistoryTracker.addResults(Collections.singletonList(
                 falsed
-                        ? FalsingClassifier.Result.falsed(confidence, "test")
+                        ? FalsingClassifier.Result.falsed(
+                                confidence, getClass().getSimpleName(), "test")
                         : FalsingClassifier.Result.passed(confidence)),
                 mSystemClock.uptimeMillis());
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/PointerCountClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/PointerCountClassifierTest.java
index 76802f4..b8ea062 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/PointerCountClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/PointerCountClassifierTest.java
@@ -18,8 +18,10 @@
 
 import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
 
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyDouble;
+import static org.mockito.ArgumentMatchers.anyInt;
 
 import android.testing.AndroidTestingRunner;
 import android.view.MotionEvent;
@@ -50,13 +52,15 @@
 
     @Test
     public void testPass_noPointer() {
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(anyInt(), anyDouble(), anyDouble()).isFalse())
+                .isFalse();
     }
 
     @Test
     public void testPass_singlePointer() {
         mClassifier.onTouchEvent(appendDownEvent(1, 1));
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(anyInt(), anyDouble(), anyDouble()).isFalse())
+                .isFalse();
     }
 
     @Test
@@ -72,7 +76,8 @@
                 0, 0);
         mClassifier.onTouchEvent(motionEvent);
         motionEvent.recycle();
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(Classifier.GENERIC, 0.5, 1).isFalse())
+                .isTrue();
     }
 
     @Test
@@ -88,7 +93,6 @@
                 0, 0);
         mClassifier.onTouchEvent(motionEvent);
         motionEvent.recycle();
-        getDataProvider().setInteractionType(QUICK_SETTINGS);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(QUICK_SETTINGS, 0.5, 0).isFalse()).isFalse();
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/ProximityClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/ProximityClassifierTest.java
index ba8ca9a..52423bd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/ProximityClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/ProximityClassifierTest.java
@@ -51,14 +51,13 @@
     private FalsingClassifier mClassifier;
 
     private final FalsingClassifier.Result mFalsedResult =
-            FalsingClassifier.Result.falsed(1, "test");
+            FalsingClassifier.Result.falsed(1, getClass().getSimpleName() , "test");
     private final FalsingClassifier.Result mPassedResult = FalsingClassifier.Result.passed(1);
 
     @Before
     public void setup() {
         super.setup();
         MockitoAnnotations.initMocks(this);
-        when(mDataProvider.getInteractionType()).thenReturn(GENERIC);
         when(mDistanceClassifier.isLongSwipe()).thenReturn(mFalsedResult);
         mClassifier = new ProximityClassifier(
                 mDistanceClassifier, mDataProvider, new DeviceConfigProxyFake());
@@ -73,7 +72,7 @@
     public void testPass_uncovered() {
         touchDown();
         touchUp(10);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse(), is(false));
     }
 
     @Test
@@ -82,17 +81,16 @@
         mClassifier.onProximityEvent(createSensorEvent(true, 1));
         mClassifier.onProximityEvent(createSensorEvent(false, 2));
         touchUp(20);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse(), is(false));
     }
 
     @Test
     public void testPass_quickSettings() {
         touchDown();
-        when(mDataProvider.getInteractionType()).thenReturn(QUICK_SETTINGS);
         mClassifier.onProximityEvent(createSensorEvent(true, 1));
         mClassifier.onProximityEvent(createSensorEvent(false, 11));
         touchUp(10);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(QUICK_SETTINGS, 0.5, 0).isFalse(), is(false));
     }
 
     @Test
@@ -101,7 +99,7 @@
         mClassifier.onProximityEvent(createSensorEvent(true, 1));
         mClassifier.onProximityEvent(createSensorEvent(false, 11));
         touchUp(10);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse(), is(true));
     }
 
     @Test
@@ -112,7 +110,7 @@
         mClassifier.onProximityEvent(createSensorEvent(true, 96));
         mClassifier.onProximityEvent(createSensorEvent(false, 100));
         touchUp(100);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse(), is(true));
     }
 
     @Test
@@ -122,7 +120,7 @@
         mClassifier.onProximityEvent(createSensorEvent(false, 11));
         touchUp(10);
         when(mDistanceClassifier.isLongSwipe()).thenReturn(mPassedResult);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(GENERIC, 0.5, 0).isFalse(), is(false));
     }
 
     private void touchDown() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/SingleTapClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/SingleTapClassifierTest.java
index 62c876f9..1524107 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/SingleTapClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/SingleTapClassifierTest.java
@@ -16,8 +16,8 @@
 
 package com.android.systemui.classifier;
 
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.Mockito.when;
 
 import android.testing.AndroidTestingRunner;
@@ -70,14 +70,14 @@
         addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1);
         addMotionEvent(0, 1, MotionEvent.ACTION_UP, TOUCH_SLOP, 1);
 
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
 
         mMotionEvents.clear();
 
         addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1);
         addMotionEvent(0, 1, MotionEvent.ACTION_UP, -TOUCH_SLOP + 2, 1);
 
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
 
     }
 
@@ -86,14 +86,14 @@
         addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1);
         addMotionEvent(0, 1, MotionEvent.ACTION_UP, 1, TOUCH_SLOP);
 
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
 
         mMotionEvents.clear();
 
         addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1);
         addMotionEvent(0, 1, MotionEvent.ACTION_UP, 1, -TOUCH_SLOP + 2);
 
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
     }
 
 
@@ -102,14 +102,14 @@
         addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1);
         addMotionEvent(0, 1, MotionEvent.ACTION_UP, TOUCH_SLOP + 1, 1);
 
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
 
         mMotionEvents.clear();
 
         addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1);
         addMotionEvent(0, 1, MotionEvent.ACTION_UP, -TOUCH_SLOP - 1, 1);
 
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
 
     }
 
@@ -118,14 +118,14 @@
         addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1);
         addMotionEvent(0, 1, MotionEvent.ACTION_UP, 1, TOUCH_SLOP + 1);
 
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
 
         mMotionEvents.clear();
 
         addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1);
         addMotionEvent(0, 1, MotionEvent.ACTION_UP, 1, -TOUCH_SLOP - 1);
 
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
     }
 
     @Test
@@ -134,7 +134,7 @@
         addMotionEvent(0, 1, MotionEvent.ACTION_MOVE, 1, TOUCH_SLOP + 1);
         addMotionEvent(0, 2, MotionEvent.ACTION_UP, 1, 1);
 
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
     }
 
     @Test
@@ -142,12 +142,12 @@
         addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1);
         addMotionEvent(0, 1, MotionEvent.ACTION_UP, 1, 1);
 
-        assertThat(mClassifier.isTap(mMotionEvents).isFalse(), is(false));
+        assertThat(mClassifier.isTap(mMotionEvents).isFalse()).isFalse();
 
         addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1);
         addMotionEvent(0, 1, MotionEvent.ACTION_UP, 1, TOUCH_SLOP + 1);
 
-        assertThat(mClassifier.isTap(mMotionEvents).isFalse(), is(true));
+        assertThat(mClassifier.isTap(mMotionEvents).isFalse()).isTrue();
 
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/TypeClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/TypeClassifierTest.java
index 4a896a8..068a1e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/TypeClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/TypeClassifierTest.java
@@ -25,8 +25,8 @@
 import static com.android.systemui.classifier.Classifier.RIGHT_AFFORDANCE;
 import static com.android.systemui.classifier.Classifier.UNLOCK;
 
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.Mockito.when;
 
 import android.testing.AndroidTestingRunner;
@@ -56,248 +56,225 @@
 
     @Test
     public void testPass_QuickSettings() {
-        when(mDataProvider.getInteractionType()).thenReturn(QUICK_SETTINGS);
         when(mDataProvider.isVertical()).thenReturn(true);
         when(mDataProvider.isUp()).thenReturn(false);
 
         when(mDataProvider.isRight()).thenReturn(false);  // right should cause no effect.
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(QUICK_SETTINGS, 0.5, 0).isFalse()).isFalse();
 
         when(mDataProvider.isRight()).thenReturn(true);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(QUICK_SETTINGS, 0.5, 0).isFalse()).isFalse();
     }
 
     @Test
     public void testFalse_QuickSettings() {
-        when(mDataProvider.getInteractionType()).thenReturn(QUICK_SETTINGS);
-
         when(mDataProvider.isVertical()).thenReturn(false);
         when(mDataProvider.isUp()).thenReturn(false);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(QUICK_SETTINGS, 0.5, 0).isFalse()).isTrue();
 
         when(mDataProvider.isVertical()).thenReturn(true);
         when(mDataProvider.isUp()).thenReturn(true);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(QUICK_SETTINGS, 0.5, 0).isFalse()).isTrue();
     }
 
     @Test
     public void testPass_PulseExpand() {
-        when(mDataProvider.getInteractionType()).thenReturn(PULSE_EXPAND);
         when(mDataProvider.isVertical()).thenReturn(true);
         when(mDataProvider.isUp()).thenReturn(false);
 
         when(mDataProvider.isRight()).thenReturn(false);  // right should cause no effect.
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(PULSE_EXPAND, 0.5, 0).isFalse()).isFalse();
 
         when(mDataProvider.isRight()).thenReturn(true);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(PULSE_EXPAND, 0.5, 0).isFalse()).isFalse();
     }
 
     @Test
     public void testFalse_PulseExpand() {
-        when(mDataProvider.getInteractionType()).thenReturn(PULSE_EXPAND);
-
         when(mDataProvider.isVertical()).thenReturn(false);
         when(mDataProvider.isUp()).thenReturn(false);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(PULSE_EXPAND, 0.5, 0).isFalse()).isTrue();
 
         when(mDataProvider.isVertical()).thenReturn(true);
         when(mDataProvider.isUp()).thenReturn(true);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(PULSE_EXPAND, 0.5, 0).isFalse()).isTrue();
     }
 
     @Test
     public void testPass_NotificationDragDown() {
-        when(mDataProvider.getInteractionType()).thenReturn(NOTIFICATION_DRAG_DOWN);
         when(mDataProvider.isVertical()).thenReturn(true);
         when(mDataProvider.isUp()).thenReturn(false);
 
         when(mDataProvider.isRight()).thenReturn(false);  // right should cause no effect.
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(NOTIFICATION_DRAG_DOWN, 0.5, 0).isFalse()).isFalse();
 
         when(mDataProvider.isRight()).thenReturn(true);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(NOTIFICATION_DRAG_DOWN, 0.5, 0).isFalse()).isFalse();
     }
 
     @Test
     public void testFalse_NotificationDragDown() {
-        when(mDataProvider.getInteractionType()).thenReturn(NOTIFICATION_DRAG_DOWN);
-
         when(mDataProvider.isVertical()).thenReturn(false);
         when(mDataProvider.isUp()).thenReturn(false);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(NOTIFICATION_DRAG_DOWN, 0.5, 0).isFalse()).isTrue();
 
         when(mDataProvider.isVertical()).thenReturn(true);
         when(mDataProvider.isUp()).thenReturn(true);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(NOTIFICATION_DRAG_DOWN, 0.5, 0).isFalse()).isTrue();
     }
 
     @Test
     public void testPass_NotificationDismiss() {
-        when(mDataProvider.getInteractionType()).thenReturn(NOTIFICATION_DISMISS);
         when(mDataProvider.isVertical()).thenReturn(false);
 
         when(mDataProvider.isUp()).thenReturn(false);  // up and right should cause no effect.
         when(mDataProvider.isRight()).thenReturn(false);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(NOTIFICATION_DISMISS, 0.5, 0).isFalse()).isFalse();
 
         when(mDataProvider.isUp()).thenReturn(true);
         when(mDataProvider.isRight()).thenReturn(false);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(NOTIFICATION_DISMISS, 0.5, 0).isFalse()).isFalse();
 
         when(mDataProvider.isUp()).thenReturn(false);
         when(mDataProvider.isRight()).thenReturn(true);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(NOTIFICATION_DISMISS, 0.5, 0).isFalse()).isFalse();
 
         when(mDataProvider.isUp()).thenReturn(true);
         when(mDataProvider.isRight()).thenReturn(true);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(NOTIFICATION_DISMISS, 0.5, 0).isFalse()).isFalse();
     }
 
     @Test
     public void testFalse_NotificationDismiss() {
-        when(mDataProvider.getInteractionType()).thenReturn(NOTIFICATION_DISMISS);
         when(mDataProvider.isVertical()).thenReturn(true);
 
         when(mDataProvider.isUp()).thenReturn(false);  // up and right should cause no effect.
         when(mDataProvider.isRight()).thenReturn(false);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(NOTIFICATION_DISMISS, 0.5, 0).isFalse()).isTrue();
 
         when(mDataProvider.isUp()).thenReturn(true);
         when(mDataProvider.isRight()).thenReturn(false);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(NOTIFICATION_DISMISS, 0.5, 0).isFalse()).isTrue();
 
         when(mDataProvider.isUp()).thenReturn(false);
         when(mDataProvider.isRight()).thenReturn(true);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(NOTIFICATION_DISMISS, 0.5, 0).isFalse()).isTrue();
 
         when(mDataProvider.isUp()).thenReturn(true);
         when(mDataProvider.isRight()).thenReturn(true);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(NOTIFICATION_DISMISS, 0.5, 0).isFalse()).isTrue();
     }
 
 
     @Test
     public void testPass_Unlock() {
-        when(mDataProvider.getInteractionType()).thenReturn(UNLOCK);
         when(mDataProvider.isVertical()).thenReturn(true);
         when(mDataProvider.isUp()).thenReturn(true);
 
 
         when(mDataProvider.isRight()).thenReturn(false);  // right should cause no effect.
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(UNLOCK, 0.5, 0).isFalse()).isFalse();
 
         when(mDataProvider.isRight()).thenReturn(true);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(UNLOCK, 0.5, 0).isFalse()).isFalse();
     }
 
     @Test
     public void testFalse_Unlock() {
-        when(mDataProvider.getInteractionType()).thenReturn(UNLOCK);
-
         when(mDataProvider.isVertical()).thenReturn(false);
         when(mDataProvider.isUp()).thenReturn(true);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(UNLOCK, 0.5, 0).isFalse()).isTrue();
 
         when(mDataProvider.isVertical()).thenReturn(true);
         when(mDataProvider.isUp()).thenReturn(false);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(UNLOCK, 0.5, 0).isFalse()).isTrue();
 
         when(mDataProvider.isVertical()).thenReturn(false);
         when(mDataProvider.isUp()).thenReturn(false);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(UNLOCK, 0.5, 0).isFalse()).isTrue();
     }
 
     @Test
     public void testPass_BouncerUnlock() {
-        when(mDataProvider.getInteractionType()).thenReturn(BOUNCER_UNLOCK);
         when(mDataProvider.isVertical()).thenReturn(true);
         when(mDataProvider.isUp()).thenReturn(true);
 
 
         when(mDataProvider.isRight()).thenReturn(false);  // right should cause no effect.
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(BOUNCER_UNLOCK, 0.5, 0).isFalse()).isFalse();
 
         when(mDataProvider.isRight()).thenReturn(true);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(BOUNCER_UNLOCK, 0.5, 0).isFalse()).isFalse();
     }
 
     @Test
     public void testFalse_BouncerUnlock() {
-        when(mDataProvider.getInteractionType()).thenReturn(BOUNCER_UNLOCK);
-
         when(mDataProvider.isVertical()).thenReturn(false);
         when(mDataProvider.isUp()).thenReturn(true);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(BOUNCER_UNLOCK, 0.5, 0).isFalse()).isTrue();
 
         when(mDataProvider.isVertical()).thenReturn(true);
         when(mDataProvider.isUp()).thenReturn(false);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(BOUNCER_UNLOCK, 0.5, 0).isFalse()).isTrue();
 
         when(mDataProvider.isVertical()).thenReturn(false);
         when(mDataProvider.isUp()).thenReturn(false);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(BOUNCER_UNLOCK, 0.5, 0).isFalse()).isTrue();
     }
 
     @Test
     public void testPass_LeftAffordance() {
-        when(mDataProvider.getInteractionType()).thenReturn(LEFT_AFFORDANCE);
         when(mDataProvider.isUp()).thenReturn(true);
         when(mDataProvider.isRight()).thenReturn(true);
 
 
         when(mDataProvider.isVertical()).thenReturn(false);  // vertical should cause no effect.
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(LEFT_AFFORDANCE, 0.5, 0).isFalse()).isFalse();
 
         when(mDataProvider.isVertical()).thenReturn(true);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(LEFT_AFFORDANCE, 0.5, 0).isFalse()).isFalse();
     }
 
     @Test
     public void testFalse_LeftAffordance() {
-        when(mDataProvider.getInteractionType()).thenReturn(LEFT_AFFORDANCE);
-
         when(mDataProvider.isRight()).thenReturn(false);
         when(mDataProvider.isUp()).thenReturn(true);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(LEFT_AFFORDANCE, 0.5, 0).isFalse()).isTrue();
 
         when(mDataProvider.isRight()).thenReturn(true);
         when(mDataProvider.isUp()).thenReturn(false);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(LEFT_AFFORDANCE, 0.5, 0).isFalse()).isTrue();
 
         when(mDataProvider.isRight()).thenReturn(false);
         when(mDataProvider.isUp()).thenReturn(false);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(LEFT_AFFORDANCE, 0.5, 0).isFalse()).isTrue();
     }
 
     @Test
     public void testPass_RightAffordance() {
-        when(mDataProvider.getInteractionType()).thenReturn(RIGHT_AFFORDANCE);
         when(mDataProvider.isUp()).thenReturn(true);
         when(mDataProvider.isRight()).thenReturn(false);
 
 
         when(mDataProvider.isVertical()).thenReturn(false);  // vertical should cause no effect.
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(RIGHT_AFFORDANCE, 0.5, 0).isFalse()).isFalse();
 
         when(mDataProvider.isVertical()).thenReturn(true);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(RIGHT_AFFORDANCE, 0.5, 0).isFalse()).isFalse();
     }
 
     @Test
     public void testFalse_RightAffordance() {
-        when(mDataProvider.getInteractionType()).thenReturn(RIGHT_AFFORDANCE);
-
         when(mDataProvider.isUp()).thenReturn(true);
         when(mDataProvider.isRight()).thenReturn(true);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(RIGHT_AFFORDANCE, 0.5, 0).isFalse()).isTrue();
 
         when(mDataProvider.isUp()).thenReturn(false);
         when(mDataProvider.isRight()).thenReturn(true);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(RIGHT_AFFORDANCE, 0.5, 0).isFalse()).isTrue();
 
         when(mDataProvider.isUp()).thenReturn(false);
         when(mDataProvider.isRight()).thenReturn(true);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(RIGHT_AFFORDANCE, 0.5, 0).isFalse()).isTrue();
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java
index 09bee12..e004c30 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java
@@ -16,8 +16,7 @@
 
 package com.android.systemui.classifier;
 
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
+import static com.google.common.truth.Truth.assertThat;
 
 import android.testing.AndroidTestingRunner;
 
@@ -51,11 +50,11 @@
 
     @Test
     public void testPass_fewTouchesVertical() {
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
         appendMoveEvent(0, 0);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
         appendMoveEvent(0, 100);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
     }
 
     @Test
@@ -63,16 +62,16 @@
         appendMoveEvent(0, 0);
         appendMoveEvent(0, 100);
         appendMoveEvent(0, 200);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
     }
 
     @Test
     public void testPass_fewTouchesHorizontal() {
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
         appendMoveEvent(0, 0);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
         appendMoveEvent(100, 0);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
     }
 
     @Test
@@ -80,7 +79,7 @@
         appendMoveEvent(0, 0);
         appendMoveEvent(100, 0);
         appendMoveEvent(200, 0);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
     }
 
 
@@ -89,7 +88,7 @@
         appendMoveEvent(0, 0);
         appendMoveEvent(0, 100);
         appendMoveEvent(0, 1);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
     }
 
     @Test
@@ -97,7 +96,7 @@
         appendMoveEvent(0, 0);
         appendMoveEvent(100, 0);
         appendMoveEvent(1, 0);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
     }
 
     @Test
@@ -105,7 +104,7 @@
         appendMoveEvent(0, 0);
         appendMoveEvent(10, 10);
         appendMoveEvent(20, 20);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
     }
 
     @Test
@@ -115,7 +114,7 @@
         appendMoveEvent(0, 0);
         appendMoveEvent(5, 100);
         appendMoveEvent(-5, 200);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
     }
 
     @Test
@@ -125,7 +124,7 @@
         appendMoveEvent(0, 0);
         appendMoveEvent(100, 5);
         appendMoveEvent(200, -5);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
     }
 
     @Test
@@ -135,7 +134,7 @@
         appendMoveEvent(0, 0);
         appendMoveEvent(6, 10);
         appendMoveEvent(-6, 20);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
     }
 
     @Test
@@ -145,7 +144,7 @@
         appendMoveEvent(0, 0);
         appendMoveEvent(10, 5);
         appendMoveEvent(20, -5);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
     }
 
     @Test
@@ -153,25 +152,25 @@
         appendMoveEvent(0, 0);
         appendMoveEvent(100, 5);
         appendMoveEvent(200, 10);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
 
         resetDataProvider();
         appendMoveEvent(0, 0);
         appendMoveEvent(100, 0);
         appendMoveEvent(200, 10);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
 
         resetDataProvider();
         appendMoveEvent(0, 0);
         appendMoveEvent(100, -10);
         appendMoveEvent(200, 10);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
 
         resetDataProvider();
         appendMoveEvent(0, 0);
         appendMoveEvent(100, -10);
         appendMoveEvent(200, 50);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
     }
 
     @Test
@@ -179,25 +178,25 @@
         appendMoveEvent(0, 0);
         appendMoveEvent(10, 50);
         appendMoveEvent(8, 100);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
 
         resetDataProvider();
         appendMoveEvent(0, 0);
         appendMoveEvent(1, 800);
         appendMoveEvent(2, 900);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
 
         resetDataProvider();
         appendMoveEvent(0, 0);
         appendMoveEvent(-10, 600);
         appendMoveEvent(30, 700);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
 
         resetDataProvider();
         appendMoveEvent(0, 0);
         appendMoveEvent(40, 100);
         appendMoveEvent(0, 101);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
     }
 
     @Test
@@ -205,25 +204,25 @@
         appendMoveEvent(0, 0);
         appendMoveEvent(-10, 50);
         appendMoveEvent(-24, 100);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
 
         resetDataProvider();
         appendMoveEvent(0, 0);
         appendMoveEvent(-20, 800);
         appendMoveEvent(-20, 900);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
 
         resetDataProvider();
         appendMoveEvent(0, 0);
         appendMoveEvent(30, 600);
         appendMoveEvent(-10, 700);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
 
         resetDataProvider();
         appendMoveEvent(0, 0);
         appendMoveEvent(-80, 100);
         appendMoveEvent(-10, 101);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
     }
 
     @Test
@@ -231,25 +230,25 @@
         appendMoveEvent(0, 0);
         appendMoveEvent(-120, 10);
         appendMoveEvent(-200, 20);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
 
         resetDataProvider();
         appendMoveEvent(0, 0);
         appendMoveEvent(-20, 8);
         appendMoveEvent(-40, 2);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
 
         resetDataProvider();
         appendMoveEvent(0, 0);
         appendMoveEvent(-500, -2);
         appendMoveEvent(-600, 70);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
 
         resetDataProvider();
         appendMoveEvent(0, 0);
         appendMoveEvent(-80, 100);
         appendMoveEvent(-100, 1);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
     }
 
     @Test
@@ -257,25 +256,25 @@
         appendMoveEvent(0, 0);
         appendMoveEvent(-120, -10);
         appendMoveEvent(-200, -20);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
 
         resetDataProvider();
         appendMoveEvent(0, 0);
         appendMoveEvent(-20, -8);
         appendMoveEvent(-40, -2);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
 
         resetDataProvider();
         appendMoveEvent(0, 0);
         appendMoveEvent(-500, 2);
         appendMoveEvent(-600, -70);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
 
         resetDataProvider();
         appendMoveEvent(0, 0);
         appendMoveEvent(-80, -100);
         appendMoveEvent(-100, -1);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
     }
 
     @Test
@@ -283,25 +282,25 @@
         appendMoveEvent(0, 0);
         appendMoveEvent(-12, -20);
         appendMoveEvent(-20, -40);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
 
         resetDataProvider();
         appendMoveEvent(0, 0);
         appendMoveEvent(-20, -130);
         appendMoveEvent(-40, -260);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
 
         resetDataProvider();
         appendMoveEvent(0, 0);
         appendMoveEvent(1, -100);
         appendMoveEvent(-6, -200);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
 
         resetDataProvider();
         appendMoveEvent(0, 0);
         appendMoveEvent(-80, -100);
         appendMoveEvent(-10, -110);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
     }
 
     @Test
@@ -309,25 +308,25 @@
         appendMoveEvent(0, 0);
         appendMoveEvent(12, -20);
         appendMoveEvent(20, -40);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
 
         resetDataProvider();
         appendMoveEvent(0, 0);
         appendMoveEvent(20, -130);
         appendMoveEvent(40, -260);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
 
         resetDataProvider();
         appendMoveEvent(0, 0);
         appendMoveEvent(-1, -100);
         appendMoveEvent(6, -200);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
 
         resetDataProvider();
         appendMoveEvent(0, 0);
         appendMoveEvent(80, -100);
         appendMoveEvent(10, -110);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
     }
 
     @Test
@@ -335,25 +334,25 @@
         appendMoveEvent(0, 0);
         appendMoveEvent(120, -20);
         appendMoveEvent(200, -40);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
 
         resetDataProvider();
         appendMoveEvent(0, 0);
         appendMoveEvent(200, -13);
         appendMoveEvent(400, -30);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
 
         resetDataProvider();
         appendMoveEvent(0, 0);
         appendMoveEvent(100, 10);
         appendMoveEvent(600, -20);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(false));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
 
         resetDataProvider();
         appendMoveEvent(0, 0);
         appendMoveEvent(80, -100);
         appendMoveEvent(100, -1);
-        assertThat(mClassifier.classifyGesture().isFalse(), is(true));
+        assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
index e761da4..c29b812 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
@@ -45,6 +45,7 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.Dependency;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
 import com.android.systemui.accessibility.SystemActions;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -93,6 +94,7 @@
                         mock(MetricsLogger.class),
                         mock(OverviewProxyService.class),
                         mock(NavigationModeController.class),
+                        mock(AccessibilityButtonModeObserver.class),
                         mock(StatusBarStateController.class),
                         mock(SysUiState.class),
                         mock(BroadcastDispatcher.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index 22c553b..f0c48bd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -67,6 +67,7 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.SysuiTestableContext;
+import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
 import com.android.systemui.accessibility.SystemActions;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -259,6 +260,7 @@
                 new MetricsLogger(),
                 mOverviewProxyService,
                 mock(NavigationModeController.class),
+                mock(AccessibilityButtonModeObserver.class),
                 mock(StatusBarStateController.class),
                 mMockSysUiState,
                 mBroadcastDispatcher,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleProviderTest.java
index b3ad6ef..24a63e7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleProviderTest.java
@@ -37,6 +37,7 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.shared.system.PeopleProviderUtils;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
 
 import junit.framework.Assert;
 
@@ -73,6 +74,8 @@
     private PackageManager mPackageManager;
     @Mock
     private IPeopleManager mPeopleManager;
+    @Mock
+    private NotificationEntryManager mNotificationEntryManager;
 
     @Before
     public void setUp() throws Exception {
@@ -84,6 +87,7 @@
                 mContext, PeopleProviderUtils.PEOPLE_PROVIDER_AUTHORITY);
         provider.setLauncherApps(mLauncherApps);
         provider.setPeopleManager(mPeopleManager);
+        provider.setNotificationEntryManager(mNotificationEntryManager);
         mContext.getContentResolver().addProvider(
                 PeopleProviderUtils.PEOPLE_PROVIDER_AUTHORITY, provider);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleProviderTestable.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleProviderTestable.java
index ac18934..6834fa5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleProviderTestable.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleProviderTestable.java
@@ -21,6 +21,8 @@
 import android.content.pm.LauncherApps;
 import android.content.pm.ProviderInfo;
 
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+
 public class PeopleProviderTestable extends PeopleProvider {
 
     public void initializeForTesting(Context context, String authority) {
@@ -37,4 +39,8 @@
     void setPeopleManager(IPeopleManager peopleManager) {
         mPeopleManager = peopleManager;
     }
+
+    void setNotificationEntryManager(NotificationEntryManager notificationEntryManager) {
+        mNotificationEntryManager = notificationEntryManager;
+    }
 }
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 410a809..ee98a59 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
@@ -25,7 +25,6 @@
 
 import static com.android.systemui.people.PeopleSpaceUtils.PACKAGE_NAME;
 import static com.android.systemui.people.PeopleSpaceUtils.REQUIRED_WIDTH_FOR_MEDIUM;
-import static com.android.systemui.people.PeopleSpaceUtils.getPeopleTileFromPersistentStorage;
 import static com.android.systemui.people.widget.AppWidgetOptionsHelper.OPTIONS_PEOPLE_TILE;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -68,15 +67,15 @@
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.provider.ContactsContract;
-import android.provider.Settings;
 import android.service.notification.ConversationChannelWrapper;
 import android.service.notification.StatusBarNotification;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.view.View;
 import android.widget.RemoteViews;
 import android.widget.TextView;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.internal.appwidget.IAppWidgetService;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
@@ -98,8 +97,8 @@
 import java.util.Map;
 import java.util.stream.Collectors;
 
-@SmallTest
 @RunWith(AndroidTestingRunner.class)
+@SmallTest
 public class PeopleSpaceUtilsTest extends SysuiTestCase {
 
     private static final int WIDGET_ID_WITH_SHORTCUT = 1;
@@ -234,8 +233,6 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        Settings.Global.putInt(mContext.getContentResolver(),
-                Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0);
 
         int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
         mOptions = new Bundle();
@@ -578,6 +575,25 @@
     }
 
     @Test
+    public void testAugmentSingleTileFromVisibleNotificationsSingleTile() {
+        PeopleSpaceTile tile =
+                new PeopleSpaceTile
+                        .Builder(SHORTCUT_ID_1, "userName", ICON, new Intent())
+                        .setPackageName(PACKAGE_NAME)
+                        .setUserHandle(new UserHandle(0))
+                        .build();
+        PeopleSpaceTile augmentedTile = PeopleSpaceUtils
+                .augmentSingleTileFromVisibleNotifications(
+                        mContext, tile, mNotificationEntryManager);
+
+        assertThat(augmentedTile).isNotNull();
+        assertThat(augmentedTile.getNotificationContent().toString())
+                .isEqualTo(NOTIFICATION_TEXT_2);
+
+        verify(mNotificationEntryManager, times(1)).getVisibleNotifications();
+    }
+
+    @Test
     public void testDoNotUpdateSingleConversationAppWidgetWhenNotBirthday() {
         int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT};
         when(mMockCursor.moveToNext()).thenReturn(true, false);
@@ -890,23 +906,6 @@
                 smallResult.findViewById(R.id.person_icon).getVisibility());
     }
 
-    @Test
-    public void testGetPeopleTileFromPersistentStorageExistingConversation()
-            throws Exception {
-        when(mPeopleManager.getConversation(PACKAGE_NAME, 0, SHORTCUT_ID_1)).thenReturn(
-                getConversationChannelWithoutTimestamp(SHORTCUT_ID_1));
-        PeopleTileKey key = new PeopleTileKey(SHORTCUT_ID_1, 0, PACKAGE_NAME);
-        PeopleSpaceTile tile = getPeopleTileFromPersistentStorage(mContext, key, mPeopleManager);
-        assertThat(tile.getId()).isEqualTo(key.getShortcutId());
-    }
-
-    @Test
-    public void testGetPeopleTileFromPersistentStorageNoConversation() {
-        PeopleTileKey key = new PeopleTileKey(SHORTCUT_ID_2, 0, PACKAGE_NAME);
-        PeopleSpaceTile tile = getPeopleTileFromPersistentStorage(mContext, key, mPeopleManager);
-        assertThat(tile).isNull();
-    }
-
     private ConversationChannelWrapper getConversationChannelWrapper(String shortcutId,
             boolean importantConversation, long lastInteractionTimestamp) throws Exception {
         ConversationChannelWrapper convo = new ConversationChannelWrapper();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java
index fce0217..0ef3ca2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java
@@ -20,11 +20,14 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.content.Intent;
+import android.os.Bundle;
 import android.os.UserHandle;
 import android.service.notification.NotificationListenerService;
 import android.testing.AndroidTestingRunner;
@@ -37,6 +40,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.wmshell.BubblesManager;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -46,6 +50,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.Optional;
+
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
@@ -55,7 +61,7 @@
     private static final String NOTIF_KEY = "notifKey";
     private static final String NOTIF_KEY_NO_ENTRY = "notifKeyNoEntry";
     private static final String NOTIF_KEY_NO_RANKING = "notifKeyNoRanking";
-
+    private static final String NOTIF_KEY_CAN_BUBBLE = "notifKeyCanBubble";
 
     private static final UserHandle USER_HANDLE = UserHandle.of(0);
     private static final int NOTIF_COUNT = 10;
@@ -72,16 +78,27 @@
     @Mock
     private NotificationEntry mNotifEntryNoRanking;
     @Mock
+    private NotificationEntry mNotifEntryCanBubble;
+    @Mock
+    private BubblesManager mBubblesManager;
+    @Mock
     private NotificationListenerService.Ranking mRanking;
 
     @Captor
     private ArgumentCaptor<NotificationVisibility> mNotificationVisibilityCaptor;
 
+    private Intent mIntent;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mActivity = new LaunchConversationActivity(mNotificationEntryManager);
+        mActivity = new LaunchConversationActivity(mNotificationEntryManager,
+                Optional.of(mBubblesManager));
+        mActivity.setIsForTesting(true, mIStatusBarService);
+        mIntent = new Intent();
+        mIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_TILE_ID, "tile ID");
+        mIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_PACKAGE_NAME, PACKAGE_NAME);
+        mIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_USER_HANDLE, USER_HANDLE);
 
         when(mNotificationEntryManager.getActiveNotificationsCount()).thenReturn(NOTIF_COUNT);
         when(mNotificationEntryManager.getPendingOrActiveNotif(NOTIF_KEY)).thenReturn(mNotifEntry);
@@ -89,15 +106,21 @@
                 .thenReturn(null);
         when(mNotificationEntryManager.getPendingOrActiveNotif(NOTIF_KEY_NO_RANKING))
                 .thenReturn(mNotifEntryNoRanking);
+        when(mNotificationEntryManager.getPendingOrActiveNotif(NOTIF_KEY_CAN_BUBBLE))
+                .thenReturn(mNotifEntryCanBubble);
         when(mNotifEntry.getRanking()).thenReturn(mRanking);
+        when(mNotifEntryCanBubble.getRanking()).thenReturn(mRanking);
+        when(mNotifEntryCanBubble.canBubble()).thenReturn(true);
         when(mNotifEntryNoRanking.getRanking()).thenReturn(null);
         when(mRanking.getRank()).thenReturn(NOTIF_RANK);
     }
 
     @Test
     public void testDoNotClearNotificationIfNoKey() throws Exception {
-        mActivity.clearNotificationIfPresent(mIStatusBarService,
-                EMPTY_STRING, PACKAGE_NAME, USER_HANDLE);
+        mIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_NOTIFICATION_KEY,
+                EMPTY_STRING);
+        mActivity.setIntent(mIntent);
+        mActivity.onCreate(new Bundle());
 
         verify(mIStatusBarService, never()).onNotificationClear(
                 any(), anyInt(), any(), anyInt(), anyInt(), any());
@@ -105,8 +128,10 @@
 
     @Test
     public void testDoNotClearNotificationIfNoNotificationEntry() throws Exception {
-        mActivity.clearNotificationIfPresent(mIStatusBarService,
-                NOTIF_KEY_NO_ENTRY, PACKAGE_NAME, USER_HANDLE);
+        mIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_NOTIFICATION_KEY,
+                NOTIF_KEY_NO_ENTRY);
+        mActivity.setIntent(mIntent);
+        mActivity.onCreate(new Bundle());
 
         verify(mIStatusBarService, never()).onNotificationClear(
                 any(), anyInt(), any(), anyInt(), anyInt(), any());
@@ -114,24 +139,41 @@
 
     @Test
     public void testDoNotClearNotificationIfNoRanking() throws Exception {
-        mActivity.clearNotificationIfPresent(mIStatusBarService,
-                NOTIF_KEY_NO_RANKING, PACKAGE_NAME, USER_HANDLE);
+        mIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_NOTIFICATION_KEY,
+                NOTIF_KEY_NO_RANKING);
+        mActivity.setIntent(mIntent);
+        mActivity.onCreate(new Bundle());
 
         verify(mIStatusBarService, never()).onNotificationClear(
                 any(), anyInt(), any(), anyInt(), anyInt(), any());
     }
 
     @Test
-    public void testClearNotification() throws Exception {
-        mActivity.clearNotificationIfPresent(mIStatusBarService,
-                NOTIF_KEY, PACKAGE_NAME, USER_HANDLE);
+    public void testEntryClearsNotificationAndDoesNotOpenBubble() throws Exception {
+        mIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_NOTIFICATION_KEY,
+                NOTIF_KEY);
+        mActivity.setIntent(mIntent);
+        mActivity.onCreate(new Bundle());
 
         verify(mIStatusBarService, times(1)).onNotificationClear(any(),
                 anyInt(), any(), anyInt(), anyInt(), mNotificationVisibilityCaptor.capture());
+        verify(mBubblesManager, never()).expandStackAndSelectBubble(any());
 
         NotificationVisibility nv = mNotificationVisibilityCaptor.getValue();
         assertThat(nv.count).isEqualTo(NOTIF_COUNT);
         assertThat(nv.rank).isEqualTo(NOTIF_RANK);
     }
 
+    @Test
+    public void testBubbleEntryOpensBubbleAndDoesNotClearNotification() throws Exception {
+        mIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_NOTIFICATION_KEY,
+                NOTIF_KEY_CAN_BUBBLE);
+        mActivity.setIntent(mIntent);
+        mActivity.onCreate(new Bundle());
+
+        // Don't clear the notification for bubbles.
+        verify(mIStatusBarService, never()).onNotificationClear(any(),
+                anyInt(), any(), anyInt(), anyInt(), any());
+        verify(mBubblesManager, times(1)).expandStackAndSelectBubble(eq(mNotifEntryCanBubble));
+    }
 }
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 096e51b..7090e78 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
@@ -60,7 +60,6 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.UserHandle;
-import android.provider.Settings;
 import android.service.notification.StatusBarNotification;
 import android.testing.AndroidTestingRunner;
 
@@ -73,6 +72,7 @@
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
 import com.android.systemui.statusbar.SbnBuilder;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NoManSimulator;
 import com.android.systemui.statusbar.notification.collection.NoManSimulator.NotifEvent;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
@@ -134,6 +134,9 @@
     private PeopleSpaceWidgetManager mManager;
 
     @Mock
+    private Context mMockContext;
+
+    @Mock
     private NotificationListener mListenerService;
 
     @Mock
@@ -144,6 +147,8 @@
     private PeopleManager mPeopleManager;
     @Mock
     private LauncherApps mLauncherApps;
+    @Mock
+    private NotificationEntryManager mNotificationEntryManager;
 
     @Captor
     private ArgumentCaptor<NotificationHandler> mListenerCaptor;
@@ -159,10 +164,10 @@
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         mLauncherApps = mock(LauncherApps.class);
-        mManager =
-                new PeopleSpaceWidgetManager(mContext);
+        mDependency.injectTestDependency(NotificationEntryManager.class, mNotificationEntryManager);
+        mManager = new PeopleSpaceWidgetManager(mContext);
         mManager.setAppWidgetManager(mAppWidgetManager, mIPeopleManager, mPeopleManager,
-                mLauncherApps);
+                mLauncherApps, mNotificationEntryManager);
         mManager.attach(mListenerService);
         mProvider = new PeopleSpaceWidgetProvider();
         mProvider.setPeopleSpaceWidgetManager(mManager);
@@ -170,9 +175,6 @@
         verify(mListenerService).addNotificationHandler(mListenerCaptor.capture());
         NotificationHandler serviceListener = requireNonNull(mListenerCaptor.getValue());
         mNoMan.addListener(serviceListener);
-        // Default to single People tile widgets.
-        Settings.Global.putInt(mContext.getContentResolver(),
-                Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0);
 
         clearStorage();
         setStorageForTile(SHORTCUT_ID, TEST_PACKAGE_A, WIDGET_ID_WITH_SHORTCUT);
@@ -298,8 +300,6 @@
 
     @Test
     public void testDoNotUpdateNotificationPostedIfDifferentPackageName() throws Exception {
-        Settings.Global.putInt(mContext.getContentResolver(),
-                Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0);
         int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
         when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
 
@@ -668,17 +668,22 @@
 
         mManager.onAppWidgetOptionsChanged(SECOND_WIDGET_ID_WITH_SHORTCUT, newOptions);
 
-        verify(mAppWidgetManager, times(1)).updateAppWidgetOptions(
+        verify(mAppWidgetManager, times(2)).updateAppWidgetOptions(
                 eq(SECOND_WIDGET_ID_WITH_SHORTCUT), mBundleArgumentCaptor.capture());
-        Bundle bundle = mBundleArgumentCaptor.getValue();
-        assertThat(bundle.getString(PeopleSpaceUtils.SHORTCUT_ID, EMPTY_STRING))
+        List<Bundle> bundles = mBundleArgumentCaptor.getAllValues();
+        Bundle first = bundles.get(0);
+        assertThat(first.getString(PeopleSpaceUtils.SHORTCUT_ID, EMPTY_STRING))
                 .isEqualTo(EMPTY_STRING);
-        assertThat(bundle.getInt(USER_ID, INVALID_USER_ID)).isEqualTo(INVALID_USER_ID);
-        assertThat(bundle.getString(PACKAGE_NAME, EMPTY_STRING)).isEqualTo(EMPTY_STRING);
+        assertThat(first.getInt(USER_ID, INVALID_USER_ID)).isEqualTo(INVALID_USER_ID);
+        assertThat(first.getString(PACKAGE_NAME, EMPTY_STRING)).isEqualTo(EMPTY_STRING);
         verify(mLauncherApps, times(1)).cacheShortcuts(eq(TEST_PACKAGE_A),
                 eq(Arrays.asList(SHORTCUT_ID)), eq(UserHandle.of(0)),
                 eq(LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS));
 
+        Bundle second = bundles.get(1);
+        PeopleSpaceTile tile = second.getParcelable(OPTIONS_PEOPLE_TILE);
+        assertThat(tile.getId()).isEqualTo(SHORTCUT_ID);
+
         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
         assertThat(sp.getStringSet(KEY.toString(), new HashSet<>())).contains(
                 String.valueOf(SECOND_WIDGET_ID_WITH_SHORTCUT));
@@ -691,6 +696,52 @@
         assertThat(widgetSp.getInt(USER_ID, INVALID_USER_ID)).isEqualTo(0);
     }
 
+    @Test
+    public void testGetPeopleTileFromPersistentStorageExistingConversation()
+            throws Exception {
+        when(mIPeopleManager.getConversation(PACKAGE_NAME, 0, SHORTCUT_ID)).thenReturn(
+                getConversationWithShortcutId(SHORTCUT_ID));
+        PeopleTileKey key = new PeopleTileKey(SHORTCUT_ID, 0, PACKAGE_NAME);
+        PeopleSpaceTile tile = mManager.getTileFromPersistentStorage(key);
+        assertThat(tile.getId()).isEqualTo(key.getShortcutId());
+    }
+
+    @Test
+    public void testGetPeopleTileFromPersistentStorageNoConversation() {
+        PeopleTileKey key = new PeopleTileKey(SHORTCUT_ID, 0, PACKAGE_NAME);
+        PeopleSpaceTile tile = mManager.getTileFromPersistentStorage(key);
+        assertThat(tile).isNull();
+    }
+
+    @Test
+    public void testRequestPinAppWidgetExistingConversation() throws Exception {
+        when(mMockContext.getPackageName()).thenReturn(PACKAGE_NAME);
+        when(mMockContext.getUserId()).thenReturn(0);
+        when(mIPeopleManager.getConversation(PACKAGE_NAME, 0, SHORTCUT_ID))
+                .thenReturn(getConversationWithShortcutId(SHORTCUT_ID));
+        when(mAppWidgetManager.requestPinAppWidget(any(), any(), any())).thenReturn(true);
+
+        ShortcutInfo info = new ShortcutInfo.Builder(mMockContext, SHORTCUT_ID).build();
+        boolean valid = mManager.requestPinAppWidget(info);
+
+        assertThat(valid).isTrue();
+        verify(mAppWidgetManager, times(1)).requestPinAppWidget(
+                any(), any(), any());
+    }
+
+    @Test
+    public void testRequestPinAppWidgetNoConversation() throws Exception {
+        when(mMockContext.getPackageName()).thenReturn(PACKAGE_NAME);
+        when(mMockContext.getUserId()).thenReturn(0);
+        when(mIPeopleManager.getConversation(PACKAGE_NAME, 0, SHORTCUT_ID)).thenReturn(null);
+
+        ShortcutInfo info = new ShortcutInfo.Builder(mMockContext, SHORTCUT_ID).build();
+        boolean valid = mManager.requestPinAppWidget(info);
+
+        assertThat(valid).isFalse();
+        verify(mAppWidgetManager, never()).requestPinAppWidget(any(), any(), any());
+    }
+
     /**
      * Adds another widget for {@code PERSON_TILE} with widget ID: {@code
      * SECOND_WIDGET_ID_WITH_SHORTCUT}.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
index fb817ea..a2113b9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
@@ -242,10 +242,18 @@
         when(mMediaHost.getVisible()).thenReturn(true);
 
         when(mFeatureFlags.isTwoColumnNotificationShadeEnabled()).thenReturn(false);
+        mController = new TestableQSPanelControllerBase(mQSPanel, mQSTileHost,
+                mQSCustomizerController, mMediaHost,
+                mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager, mFeatureFlags);
+
         assertThat(mController.shouldUseHorizontalLayout()).isTrue();
 
         when(mFeatureFlags.isTwoColumnNotificationShadeEnabled()).thenReturn(true);
         when(mResources.getBoolean(R.bool.config_use_split_notification_shade)).thenReturn(true);
+        mController = new TestableQSPanelControllerBase(mQSPanel, mQSTileHost,
+                mQSCustomizerController, mMediaHost,
+                mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager, mFeatureFlags);
+
         assertThat(mController.shouldUseHorizontalLayout()).isFalse();
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
new file mode 100644
index 0000000..33166cc
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
@@ -0,0 +1,207 @@
+/*
+ * 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.tiles;
+
+import static android.content.pm.PackageManager.FEATURE_NFC_HOST_CARD_EMULATION;
+import static android.provider.Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertNull;
+import static junit.framework.TestCase.assertTrue;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+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.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.service.quickaccesswallet.QuickAccessWalletClient;
+import android.service.quicksettings.Tile;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEventLogger;
+import com.android.internal.logging.testing.UiEventLoggerFake;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingManagerFake;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.qs.QSTile;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.settings.SecureSettings;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+public class QuickAccessWalletTileTest extends SysuiTestCase {
+
+    @Mock
+    private QSTileHost mHost;
+    @Mock
+    private MetricsLogger mMetricsLogger;
+    @Mock
+    private StatusBarStateController mStatusBarStateController;
+    @Mock
+    private ActivityStarter mActivityStarter;
+    @Mock
+    private QSLogger mQSLogger;
+    private UiEventLogger mUiEventLogger = new UiEventLoggerFake();
+    @Mock
+    private QuickAccessWalletClient mQuickAccessWalletClient;
+    @Mock
+    private KeyguardStateController mKeyguardStateController;
+    @Mock
+    private PackageManager mPackageManager;
+    @Mock
+    private SecureSettings mSecureSettings;
+    @Mock
+    private FeatureFlags mFeatureFlags;
+
+    private TestableLooper mTestableLooper;
+    private QuickAccessWalletTile mTile;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mTestableLooper = TestableLooper.get(this);
+
+        when(mHost.getContext()).thenReturn(mContext);
+        when(mHost.getUiEventLogger()).thenReturn(mUiEventLogger);
+        when(mFeatureFlags.isQuickAccessWalletEnabled()).thenReturn(true);
+
+        mTile = new QuickAccessWalletTile(
+                mHost,
+                mTestableLooper.getLooper(),
+                new Handler(mTestableLooper.getLooper()),
+                new FalsingManagerFake(),
+                mMetricsLogger,
+                mStatusBarStateController,
+                mActivityStarter,
+                mQSLogger,
+                mQuickAccessWalletClient,
+                mKeyguardStateController,
+                mPackageManager,
+                mSecureSettings,
+                mFeatureFlags);
+    }
+
+    @Test
+    public void testNewTile() {
+        assertFalse(mTile.newTileState().handlesLongClick);
+    }
+
+    @Test
+    public void testIsAvailable_featureFlagIsOff() {
+        when(mFeatureFlags.isQuickAccessWalletEnabled()).thenReturn(false);
+        assertFalse(mTile.isAvailable());
+    }
+
+    @Test
+    public void testIsAvailable_qawServiceNotAvailable() {
+        when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(false);
+        assertFalse(mTile.isAvailable());
+    }
+
+    @Test
+    public void testIsAvailable_qawServiceAvailable() {
+        when(mPackageManager.hasSystemFeature(FEATURE_NFC_HOST_CARD_EMULATION)).thenReturn(true);
+        when(mPackageManager.hasSystemFeature("org.chromium.arc")).thenReturn(false);
+        when(mSecureSettings.getString(NFC_PAYMENT_DEFAULT_COMPONENT)).thenReturn("Component");
+
+        assertTrue(mTile.isAvailable());
+    }
+
+    @Test
+    public void testHandleClick_openGPay() {
+        Intent intent = new Intent("WalletIntent");
+        when(mQuickAccessWalletClient.createWalletIntent()).thenReturn(intent);
+        mTile.handleClick();
+
+        verify(mActivityStarter, times(1))
+                .postStartActivityDismissingKeyguard(eq(intent), anyInt());
+    }
+
+    @Test
+    public void testHandleUpdateState_updateLabelAndIcon() {
+        QSTile.Icon icon = QSTileImpl.ResourceIcon.get(R.drawable.ic_qs_wallet);
+        QSTile.State state = new QSTile.State();
+        when(mQuickAccessWalletClient.getServiceLabel()).thenReturn("QuickAccessWallet");
+
+        mTile.handleUpdateState(state, new Object());
+
+        assertEquals("QuickAccessWallet", state.label.toString());
+        assertTrue(state.label.toString().contentEquals(state.contentDescription));
+        assertEquals(icon, state.icon);
+    }
+
+    @Test
+    public void testHandleUpdateState_deviceLocked_tileInactive() {
+        QSTile.State state = new QSTile.State();
+        when(mKeyguardStateController.isUnlocked()).thenReturn(false);
+        when(mQuickAccessWalletClient.isWalletFeatureAvailable()).thenReturn(true);
+
+        mTile.handleUpdateState(state, new Object());
+
+        assertEquals(Tile.STATE_INACTIVE, state.state);
+        assertNull(state.stateDescription);
+    }
+
+    @Test
+    public void testHandleUpdateState_deviceLocked_tileActive() {
+        QSTile.State state = new QSTile.State();
+        when(mKeyguardStateController.isUnlocked()).thenReturn(true);
+        when(mQuickAccessWalletClient.isWalletFeatureAvailable()).thenReturn(true);
+
+        mTile.handleUpdateState(state, new Object());
+
+        assertEquals(Tile.STATE_ACTIVE, state.state);
+        assertTrue(state.secondaryLabel.toString().contentEquals(state.stateDescription));
+        assertEquals(
+                getContext().getString(R.string.wallet_secondary_label),
+                state.secondaryLabel.toString());
+    }
+
+    @Test
+    public void testHandleUpdateState_qawFeatureUnavailable_tileUnavailable() {
+        QSTile.State state = new QSTile.State();
+        when(mKeyguardStateController.isUnlocked()).thenReturn(true);
+        when(mQuickAccessWalletClient.isWalletFeatureAvailable()).thenReturn(false);
+
+        mTile.handleUpdateState(state, new Object());
+
+        assertEquals(Tile.STATE_UNAVAILABLE, state.state);
+    }
+}
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 6032e51..9799514 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
@@ -30,8 +30,8 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.R;
 import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.plugins.ActivityStarter;
@@ -99,7 +99,7 @@
 
         assertEquals(Tile.STATE_INACTIVE, mTile.getState().state);
         assertEquals(mTile.getState().label.toString(),
-                mContext.getString(R.string.quick_settings_reduce_bright_colors_label));
+                mContext.getString(R.string.reduce_bright_colors_feature_name));
     }
 
     @Test
@@ -110,7 +110,7 @@
 
         assertEquals(Tile.STATE_ACTIVE, mTile.getState().state);
         assertEquals(mTile.getState().label.toString(),
-                mContext.getString(R.string.quick_settings_reduce_bright_colors_label));
+                mContext.getString(R.string.reduce_bright_colors_feature_name));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java
deleted file mode 100644
index 25104b8..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java
+++ /dev/null
@@ -1,123 +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.systemui.recents;
-
-import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.pm.PackageManager;
-import android.os.RemoteException;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableContext;
-import android.testing.TestableLooper;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.model.SysUiState;
-import com.android.systemui.navigationbar.NavigationBarController;
-import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
-import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
-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 org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.Optional;
-
-import dagger.Lazy;
-
-/**
- * Unit tests for {@link com.android.systemui.recents.OverviewProxyService}
- */
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-public class OverviewProxyServiceTest extends SysuiTestCase {
-    private OverviewProxyService mSpiedOverviewProxyService;
-    private TestableContext mSpiedContext;
-
-    @Mock private BroadcastDispatcher mMockBroadcastDispatcher;
-    @Mock private CommandQueue mMockCommandQueue;
-    @Mock private Lazy<NavigationBarController> mMockNavBarControllerLazy;
-    @Mock private IPinnedStackAnimationListener mMockPinnedStackAnimationListener;
-    @Mock private NavigationModeController mMockNavModeController;
-    @Mock private NotificationShadeWindowController mMockStatusBarWinController;
-    @Mock private Optional<Pip> mMockPipOptional;
-    @Mock private Optional<LegacySplitScreen> mMockLegacySplitScreenOptional;
-    @Mock private Optional<SplitScreen> mMockSplitScreenOptional;
-    @Mock private Optional<Lazy<StatusBar>> mMockStatusBarOptionalLazy;
-    @Mock private Optional<com.android.wm.shell.onehanded.OneHanded> mMockOneHandedOptional;
-    @Mock private PackageManager mPackageManager;
-    @Mock private SysUiState mMockSysUiState;
-    @Mock private RemoteTransitions mMockTransitions;
-    @Mock private Optional<StartingSurface> mStartingSurface;
-
-    @Before
-    public void setUp() throws RemoteException {
-        MockitoAnnotations.initMocks(this);
-
-        mSpiedContext = spy(mContext);
-
-        when(mPackageManager.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)).thenReturn(false);
-        when(mSpiedContext.getPackageManager()).thenReturn(mPackageManager);
-
-        mSpiedOverviewProxyService = spy(new OverviewProxyService(mSpiedContext, mMockCommandQueue,
-                mMockNavBarControllerLazy, mMockNavModeController, mMockStatusBarWinController,
-                mMockSysUiState, mMockPipOptional, mMockLegacySplitScreenOptional,
-                mMockSplitScreenOptional, mMockStatusBarOptionalLazy, mMockOneHandedOptional,
-                mMockBroadcastDispatcher, mMockTransitions, mStartingSurface));
-    }
-
-    @Test
-    public void testNonPipDevice_shouldNotNotifySwipeToHomeFinished() throws RemoteException {
-        mSpiedOverviewProxyService.mSysUiProxy.notifySwipeToHomeFinished();
-
-        verify(mMockPipOptional, never()).ifPresent(any());
-    }
-
-    @Test
-    public void testNonPipDevice_shouldNotSetPinnedStackAnimationListener() throws RemoteException {
-        mSpiedOverviewProxyService.mSysUiProxy.setPinnedStackAnimationListener(
-                mMockPinnedStackAnimationListener);
-
-        verify(mMockPipOptional, never()).ifPresent(any());
-    }
-
-    @Test
-    public void testNonPipDevice_shouldNotSetShelfHeight() throws RemoteException {
-        mSpiedOverviewProxyService.mSysUiProxy.setShelfHeight(true /* visible */,
-                100 /* shelfHeight */);
-
-        verify(mMockPipOptional, never()).ifPresent(any());
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureControllerTest.java
new file mode 100644
index 0000000..410d9de
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureControllerTest.java
@@ -0,0 +1,216 @@
+/*
+ * 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.screenshot;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.hardware.HardwareBuffer;
+import android.media.Image;
+import android.testing.AndroidTestingRunner;
+import android.view.ScrollCaptureResponse;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.systemui.SysuiTestCase;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.ExecutionException;
+
+/**
+ * Tests for ScrollCaptureController which manages sequential image acquisition for long
+ * screenshots.
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class ScrollCaptureControllerTest extends SysuiTestCase {
+
+    private static class FakeSession implements ScrollCaptureClient.Session {
+        public int availableTop = Integer.MIN_VALUE;
+        public int availableBottom = Integer.MAX_VALUE;
+        // If true, return an empty rect any time a partial result would have been returned.
+        public boolean emptyInsteadOfPartial = false;
+
+        @Override
+        public ListenableFuture<ScrollCaptureClient.CaptureResult> requestTile(int top) {
+            Rect requested = new Rect(0, top, getPageWidth(), top + getTileHeight());
+            Rect fullContent = new Rect(0, availableTop, getPageWidth(), availableBottom);
+            Rect captured = new Rect(requested);
+            captured.intersect(fullContent);
+            if (emptyInsteadOfPartial && captured.height() != getTileHeight()) {
+                captured = new Rect();
+            }
+            Image image = mock(Image.class);
+            when(image.getHardwareBuffer()).thenReturn(mock(HardwareBuffer.class));
+            ScrollCaptureClient.CaptureResult result =
+                    new ScrollCaptureClient.CaptureResult(image, requested, captured);
+            return Futures.immediateFuture(result);
+        }
+
+        public int getMaxHeight() {
+            return getTileHeight() * getMaxTiles();
+        }
+
+        @Override
+        public int getMaxTiles() {
+            return 10;
+        }
+
+        @Override
+        public int getTileHeight() {
+            return 50;
+        }
+
+        @Override
+        public int getPageHeight() {
+            return 100;
+        }
+
+        @Override
+        public int getPageWidth() {
+            return 100;
+        }
+
+        @Override
+        public Rect getWindowBounds() {
+            return null;
+        }
+
+        @Override
+        public ListenableFuture<Void> end() {
+            return Futures.immediateVoidFuture();
+        }
+
+        @Override
+        public void release() {
+        }
+    }
+
+    private ScrollCaptureController mController;
+    private FakeSession mSession;
+    private ScrollCaptureClient mScrollCaptureClient;
+
+    @Before
+    public void setUp() {
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        mSession = new FakeSession();
+        mScrollCaptureClient = mock(ScrollCaptureClient.class);
+        when(mScrollCaptureClient.request(anyInt(), anyInt())).thenReturn(
+                Futures.immediateFuture(new ScrollCaptureResponse.Builder().build()));
+        when(mScrollCaptureClient.start(any(), anyFloat())).thenReturn(
+                Futures.immediateFuture(mSession));
+        mController = new ScrollCaptureController(context, context.getMainExecutor(),
+                mScrollCaptureClient, new ImageTileSet(context.getMainThreadHandler()));
+    }
+
+    @Test
+    public void testInfinite() throws ExecutionException, InterruptedException {
+        ScrollCaptureController.LongScreenshot screenshot =
+                mController.run(new ScrollCaptureResponse.Builder().build()).get();
+        assertEquals(mSession.getMaxHeight(), screenshot.getHeight());
+        // TODO: the top and bottom ratio in the infinite case should be extracted and tested.
+        assertEquals(-150, screenshot.getTop());
+        assertEquals(350, screenshot.getBottom());
+    }
+
+    @Test
+    public void testLimitedBottom() throws ExecutionException, InterruptedException {
+        // We hit the bottom of the content, so expect it to scroll back up and go above the -150
+        // default top position
+        mSession.availableBottom = 275;
+        ScrollCaptureController.LongScreenshot screenshot =
+                mController.run(new ScrollCaptureResponse.Builder().build()).get();
+        // Bottom tile will be 25px tall, 10 tiles total
+        assertEquals(mSession.getMaxHeight() - 25, screenshot.getHeight());
+        assertEquals(-200, screenshot.getTop());
+        assertEquals(mSession.availableBottom, screenshot.getBottom());
+    }
+
+    @Test
+    public void testLimitedTopAndBottom() throws ExecutionException, InterruptedException {
+        mSession.availableBottom = 275;
+        mSession.availableTop = -200;
+        ScrollCaptureController.LongScreenshot screenshot =
+                mController.run(new ScrollCaptureResponse.Builder().build()).get();
+        assertEquals(mSession.availableBottom - mSession.availableTop, screenshot.getHeight());
+        assertEquals(mSession.availableTop, screenshot.getTop());
+        assertEquals(mSession.availableBottom, screenshot.getBottom());
+    }
+
+    @Test
+    public void testVeryLimitedTopInfiniteBottom() throws ExecutionException, InterruptedException {
+        // Hit the boundary before the "headroom" is hit in the up direction, then go down
+        // infinitely.
+        mSession.availableTop = -55;
+        ScrollCaptureController.LongScreenshot screenshot =
+                mController.run(new ScrollCaptureResponse.Builder().build()).get();
+        // The top tile will be 5px tall, so subtract 45px from the theoretical max.
+        assertEquals(mSession.getMaxHeight() - 45, screenshot.getHeight());
+        assertEquals(mSession.availableTop, screenshot.getTop());
+        assertEquals(mSession.availableTop + mSession.getMaxHeight() - 45, screenshot.getBottom());
+    }
+
+    @Test
+    public void testVeryLimitedTopLimitedBottom() throws ExecutionException, InterruptedException {
+        mSession.availableBottom = 275;
+        mSession.availableTop = -55;
+        ScrollCaptureController.LongScreenshot screenshot =
+                mController.run(new ScrollCaptureResponse.Builder().build()).get();
+        assertEquals(mSession.availableBottom - mSession.availableTop, screenshot.getHeight());
+        assertEquals(mSession.availableTop, screenshot.getTop());
+        assertEquals(mSession.availableBottom, screenshot.getBottom());
+    }
+
+    @Test
+    public void testLimitedTopAndBottomWithEmpty() throws ExecutionException, InterruptedException {
+        mSession.emptyInsteadOfPartial = true;
+        mSession.availableBottom = 275;
+        mSession.availableTop = -167;
+        ScrollCaptureController.LongScreenshot screenshot =
+                mController.run(new ScrollCaptureResponse.Builder().build()).get();
+        // Expecting output from -150 to 250
+        assertEquals(400, screenshot.getHeight());
+        assertEquals(-150, screenshot.getTop());
+        assertEquals(250, screenshot.getBottom());
+    }
+
+    @Test
+    public void testVeryLimitedTopWithEmpty() throws ExecutionException, InterruptedException {
+        // Hit the boundary before the "headroom" is hit in the up direction, then go down
+        // infinitely.
+        mSession.availableTop = -55;
+        mSession.emptyInsteadOfPartial = true;
+        ScrollCaptureController.LongScreenshot screenshot =
+                mController.run(new ScrollCaptureResponse.Builder().build()).get();
+        assertEquals(mSession.getMaxHeight(), screenshot.getHeight());
+        assertEquals(-50, screenshot.getTop());
+        assertEquals(-50 + mSession.getMaxHeight(), screenshot.getBottom());
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index 8ec03d7..58738e7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -29,6 +29,7 @@
 import android.graphics.Rect;
 import android.hardware.biometrics.IBiometricSysuiReceiver;
 import android.hardware.biometrics.PromptInfo;
+import android.hardware.fingerprint.IUdfpsHbmListener;
 import android.os.Bundle;
 import android.view.WindowInsetsController.Appearance;
 import android.view.WindowInsetsController.Behavior;
@@ -464,6 +465,14 @@
     }
 
     @Test
+    public void testSetUdfpsHbmListener() {
+        final IUdfpsHbmListener listener = mock(IUdfpsHbmListener.class);
+        mCommandQueue.setUdfpsHbmListener(listener);
+        waitForIdleSync();
+        verify(mCallbacks).setUdfpsHbmListener(eq(listener));
+    }
+
+    @Test
     public void testSuppressAmbientDisplay() {
         mCommandQueue.suppressAmbientDisplay(true);
         waitForIdleSync();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt
new file mode 100644
index 0000000..3701b91
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt
@@ -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.systemui.statusbar.charging
+
+import android.testing.AndroidTestingRunner
+import android.view.View
+import android.view.ViewGroupOverlay
+import android.view.ViewRootImpl
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.statusbar.commandline.CommandRegistry
+import com.android.systemui.statusbar.policy.BatteryController
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.never
+import org.mockito.Mockito.reset
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class WiredChargingRippleControllerTest : SysuiTestCase() {
+    private lateinit var controller: WiredChargingRippleController
+    @Mock private lateinit var commandRegistry: CommandRegistry
+    @Mock private lateinit var batteryController: BatteryController
+    @Mock private lateinit var featureFlags: FeatureFlags
+    @Mock private lateinit var configurationController: ConfigurationController
+    @Mock private lateinit var keyguardStateController: KeyguardStateController
+    @Mock private lateinit var rippleView: ChargingRippleView
+    @Mock private lateinit var viewHost: View
+    @Mock private lateinit var viewHostRootImpl: ViewRootImpl
+    @Mock private lateinit var viewGroupOverlay: ViewGroupOverlay
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        `when`(viewHost.viewRootImpl).thenReturn(viewHostRootImpl)
+        `when`(viewHostRootImpl.view).thenReturn(viewHost)
+        `when`(viewHost.overlay).thenReturn(viewGroupOverlay)
+        `when`(featureFlags.isChargingRippleEnabled).thenReturn(true)
+        `when`(keyguardStateController.isShowing).thenReturn(true)
+        controller = WiredChargingRippleController(
+                commandRegistry, batteryController, configurationController,
+                featureFlags, context, keyguardStateController)
+        controller.rippleView = rippleView // Replace the real ripple view with a mock instance
+        controller.setViewHost(viewHost)
+    }
+
+    @Test
+    fun testSetRippleViewAsOverlay() {
+        val listenerCaptor = ArgumentCaptor.forClass(View.OnAttachStateChangeListener::class.java)
+        verify(viewHost).addOnAttachStateChangeListener(listenerCaptor.capture())
+
+        // Fake attach to window
+        listenerCaptor.value.onViewAttachedToWindow(viewHost)
+        verify(viewGroupOverlay).add(rippleView)
+    }
+
+    @Test
+    fun testTriggerRipple() {
+        val captor = ArgumentCaptor
+                .forClass(BatteryController.BatteryStateChangeCallback::class.java)
+        verify(batteryController).addCallback(captor.capture())
+
+        val unusedBatteryLevel = 0
+        captor.value.onBatteryLevelChanged(
+                unusedBatteryLevel,
+                false /* plugged in */,
+                false /* charging */)
+        verify(rippleView, never()).startRipple()
+
+        captor.value.onBatteryLevelChanged(
+                unusedBatteryLevel,
+                true /* plugged in */,
+                false /* charging */)
+        verify(rippleView).startRipple()
+    }
+
+    @Test
+    fun testUpdateRippleColor() {
+        val captor = ArgumentCaptor
+                .forClass(ConfigurationController.ConfigurationListener::class.java)
+        verify(configurationController).addCallback(captor.capture())
+
+        reset(rippleView)
+        captor.value.onThemeChanged()
+        verify(rippleView).setColor(ArgumentMatchers.anyInt())
+
+        reset(rippleView)
+        captor.value.onUiModeChanged()
+        verify(rippleView).setColor(ArgumentMatchers.anyInt())
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
index 5c37656..d4b21c6f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
@@ -76,6 +76,7 @@
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
 import com.android.systemui.statusbar.SbnBuilder;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
@@ -141,6 +142,8 @@
     @Mock
     private LauncherApps mLauncherApps;
     @Mock
+    private PeopleSpaceWidgetManager mPeopleSpaceWidgetManager;
+    @Mock
     private ShortcutManager mShortcutManager;
     @Mock
     private NotificationGuts mNotificationGuts;
@@ -236,6 +239,8 @@
                 .thenReturn(mock(NotificationManager.Policy.class));
 
         when(mBuilder.build()).thenReturn(mock(PriorityOnboardingDialogController.class));
+
+        when(mPeopleSpaceWidgetManager.requestPinAppWidget(any())).thenReturn(true);
     }
 
     @Test
@@ -244,6 +249,7 @@
                 -1,
                 mShortcutManager,
                 mMockPackageManager,
+                mPeopleSpaceWidgetManager,
                 mMockINotificationManager,
                 mOnUserInteractionCallback,
                 TEST_PACKAGE_NAME,
@@ -257,7 +263,8 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler, null, Optional.of(mBubblesManager));
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
         final ImageView view = mNotificationInfo.findViewById(R.id.conversation_icon);
         assertEquals(mIconDrawable, view.getDrawable());
     }
@@ -269,6 +276,7 @@
                 -1,
                 mShortcutManager,
                 mMockPackageManager,
+                mPeopleSpaceWidgetManager,
                 mMockINotificationManager,
                 mOnUserInteractionCallback,
                 TEST_PACKAGE_NAME,
@@ -282,7 +290,8 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler, null, Optional.of(mBubblesManager));
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
         final TextView textView = mNotificationInfo.findViewById(R.id.pkg_name);
         assertTrue(textView.getText().toString().contains("App Name"));
         assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
@@ -322,6 +331,7 @@
                 -1,
                 mShortcutManager,
                 mMockPackageManager,
+                mPeopleSpaceWidgetManager,
                 mMockINotificationManager,
                 mOnUserInteractionCallback,
                 TEST_PACKAGE_NAME,
@@ -335,7 +345,8 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler, null, Optional.of(mBubblesManager));
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
         final TextView textView = mNotificationInfo.findViewById(R.id.group_name);
         assertTrue(textView.getText().toString().contains(group.getName()));
         assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
@@ -348,6 +359,7 @@
                 -1,
                 mShortcutManager,
                 mMockPackageManager,
+                mPeopleSpaceWidgetManager,
                 mMockINotificationManager,
                 mOnUserInteractionCallback,
                 TEST_PACKAGE_NAME,
@@ -361,7 +373,8 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler, null, Optional.of(mBubblesManager));
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
         final TextView textView = mNotificationInfo.findViewById(R.id.group_name);
         assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
         assertEquals(GONE, textView.getVisibility());
@@ -373,6 +386,7 @@
                 -1,
                 mShortcutManager,
                 mMockPackageManager,
+                mPeopleSpaceWidgetManager,
                 mMockINotificationManager,
                 mOnUserInteractionCallback,
                 TEST_PACKAGE_NAME,
@@ -386,7 +400,8 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler, null, Optional.of(mBubblesManager));
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
         final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
         assertEquals(GONE, nameView.getVisibility());
     }
@@ -409,6 +424,7 @@
                 -1,
                 mShortcutManager,
                 mMockPackageManager,
+                mPeopleSpaceWidgetManager,
                 mMockINotificationManager,
                 mOnUserInteractionCallback,
                 TEST_PACKAGE_NAME,
@@ -422,7 +438,8 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler, null, Optional.of(mBubblesManager));
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
         final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
         assertEquals(VISIBLE, nameView.getVisibility());
         assertTrue(nameView.getText().toString().contains("Proxied"));
@@ -435,6 +452,7 @@
                 -1,
                 mShortcutManager,
                 mMockPackageManager,
+                mPeopleSpaceWidgetManager,
                 mMockINotificationManager,
                 mOnUserInteractionCallback,
                 TEST_PACKAGE_NAME,
@@ -451,7 +469,8 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler, null, Optional.of(mBubblesManager));
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
 
         final View settingsButton = mNotificationInfo.findViewById(R.id.info);
         settingsButton.performClick();
@@ -465,6 +484,7 @@
                 -1,
                 mShortcutManager,
                 mMockPackageManager,
+                mPeopleSpaceWidgetManager,
                 mMockINotificationManager,
                 mOnUserInteractionCallback,
                 TEST_PACKAGE_NAME,
@@ -478,7 +498,8 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler, null, Optional.of(mBubblesManager));
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
         final View settingsButton = mNotificationInfo.findViewById(R.id.info);
         assertTrue(settingsButton.getVisibility() != View.VISIBLE);
     }
@@ -490,6 +511,7 @@
                 -1,
                 mShortcutManager,
                 mMockPackageManager,
+                mPeopleSpaceWidgetManager,
                 mMockINotificationManager,
                 mOnUserInteractionCallback,
                 TEST_PACKAGE_NAME,
@@ -506,7 +528,8 @@
                 mBuilderProvider,
                 false,
                 mTestHandler,
-                mTestHandler, null, Optional.of(mBubblesManager));
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
         final View settingsButton = mNotificationInfo.findViewById(R.id.info);
         assertTrue(settingsButton.getVisibility() != View.VISIBLE);
     }
@@ -519,6 +542,7 @@
                 -1,
                 mShortcutManager,
                 mMockPackageManager,
+                mPeopleSpaceWidgetManager,
                 mMockINotificationManager,
                 mOnUserInteractionCallback,
                 TEST_PACKAGE_NAME,
@@ -532,7 +556,8 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler, null, Optional.of(mBubblesManager));
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
         View view = mNotificationInfo.findViewById(R.id.silence);
         assertThat(view.isSelected()).isTrue();
     }
@@ -548,6 +573,7 @@
                 -1,
                 mShortcutManager,
                 mMockPackageManager,
+                mPeopleSpaceWidgetManager,
                 mMockINotificationManager,
                 mOnUserInteractionCallback,
                 TEST_PACKAGE_NAME,
@@ -561,7 +587,8 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler, null, Optional.of(mBubblesManager));
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
         View view = mNotificationInfo.findViewById(R.id.default_behavior);
         assertThat(view.isSelected()).isTrue();
         assertThat(((TextView) view.findViewById(R.id.default_summary)).getText()).isEqualTo(
@@ -580,6 +607,7 @@
                 -1,
                 mShortcutManager,
                 mMockPackageManager,
+                mPeopleSpaceWidgetManager,
                 mMockINotificationManager,
                 mOnUserInteractionCallback,
                 TEST_PACKAGE_NAME,
@@ -593,7 +621,8 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler, null, Optional.of(mBubblesManager));
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
         View view = mNotificationInfo.findViewById(R.id.default_behavior);
         assertThat(view.isSelected()).isTrue();
         assertThat(((TextView) view.findViewById(R.id.default_summary)).getText()).isEqualTo(
@@ -611,6 +640,7 @@
                 -1,
                 mShortcutManager,
                 mMockPackageManager,
+                mPeopleSpaceWidgetManager,
                 mMockINotificationManager,
                 mOnUserInteractionCallback,
                 TEST_PACKAGE_NAME,
@@ -624,7 +654,8 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler, null, Optional.of(mBubblesManager));
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
 
         View fave = mNotificationInfo.findViewById(R.id.priority);
         fave.performClick();
@@ -656,6 +687,7 @@
                 -1,
                 mShortcutManager,
                 mMockPackageManager,
+                mPeopleSpaceWidgetManager,
                 mMockINotificationManager,
                 mOnUserInteractionCallback,
                 TEST_PACKAGE_NAME,
@@ -669,7 +701,8 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler, null, Optional.of(mBubblesManager));
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
 
         mNotificationInfo.findViewById(R.id.default_behavior).performClick();
         mTestableLooper.processAllMessages();
@@ -700,6 +733,7 @@
                 -1,
                 mShortcutManager,
                 mMockPackageManager,
+                mPeopleSpaceWidgetManager,
                 mMockINotificationManager,
                 mOnUserInteractionCallback,
                 TEST_PACKAGE_NAME,
@@ -713,7 +747,8 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler, null, Optional.of(mBubblesManager));
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
 
         View silence = mNotificationInfo.findViewById(R.id.silence);
 
@@ -745,6 +780,7 @@
                 -1,
                 mShortcutManager,
                 mMockPackageManager,
+                mPeopleSpaceWidgetManager,
                 mMockINotificationManager,
                 mOnUserInteractionCallback,
                 TEST_PACKAGE_NAME,
@@ -758,7 +794,8 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler, null, Optional.of(mBubblesManager));
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
 
         View fave = mNotificationInfo.findViewById(R.id.priority);
         fave.performClick();
@@ -783,6 +820,7 @@
                 -1,
                 mShortcutManager,
                 mMockPackageManager,
+                mPeopleSpaceWidgetManager,
                 mMockINotificationManager,
                 mOnUserInteractionCallback,
                 TEST_PACKAGE_NAME,
@@ -796,7 +834,8 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler, null, Optional.of(mBubblesManager));
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
 
         View fave = mNotificationInfo.findViewById(R.id.priority);
         fave.performClick();
@@ -820,6 +859,7 @@
                 -1,
                 mShortcutManager,
                 mMockPackageManager,
+                mPeopleSpaceWidgetManager,
                 mMockINotificationManager,
                 mOnUserInteractionCallback,
                 TEST_PACKAGE_NAME,
@@ -833,7 +873,8 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler, null, Optional.of(mBubblesManager));
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
 
         View fave = mNotificationInfo.findViewById(R.id.priority);
         fave.performClick();
@@ -861,6 +902,7 @@
                 -1, // no action selected by default
                 mShortcutManager,
                 mMockPackageManager,
+                mPeopleSpaceWidgetManager,
                 mMockINotificationManager,
                 mOnUserInteractionCallback,
                 TEST_PACKAGE_NAME,
@@ -874,7 +916,8 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler, null, Optional.of(mBubblesManager));
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
 
         // THEN the selected action is -1, so the selected option is "Default" priority
         assertEquals(mNotificationInfo.getSelectedAction(), -1);
@@ -892,6 +935,7 @@
                 NotificationConversationInfo.ACTION_FAVORITE, // "Favorite" selected by default
                 mShortcutManager,
                 mMockPackageManager,
+                mPeopleSpaceWidgetManager,
                 mMockINotificationManager,
                 mOnUserInteractionCallback,
                 TEST_PACKAGE_NAME,
@@ -905,7 +949,8 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler, null, Optional.of(mBubblesManager));
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
 
         // THEN the selected action is "Favorite", so the selected option is "priority" priority
         assertEquals(mNotificationInfo.getSelectedAction(),
@@ -922,6 +967,7 @@
                 -1,
                 mShortcutManager,
                 mMockPackageManager,
+                mPeopleSpaceWidgetManager,
                 mMockINotificationManager,
                 mOnUserInteractionCallback,
                 TEST_PACKAGE_NAME,
@@ -935,7 +981,8 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler, null, Optional.of(mBubblesManager));
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
 
         mNotificationInfo.findViewById(R.id.default_behavior).performClick();
         mNotificationInfo.findViewById(R.id.done).performClick();
@@ -959,6 +1006,7 @@
                 -1,
                 mShortcutManager,
                 mMockPackageManager,
+                mPeopleSpaceWidgetManager,
                 mMockINotificationManager,
                 mOnUserInteractionCallback,
                 TEST_PACKAGE_NAME,
@@ -972,7 +1020,8 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler, null, Optional.of(mBubblesManager));
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
 
         mNotificationInfo.findViewById(R.id.default_behavior).performClick();
         mNotificationInfo.findViewById(R.id.done).performClick();
@@ -996,6 +1045,7 @@
                 -1,
                 mShortcutManager,
                 mMockPackageManager,
+                mPeopleSpaceWidgetManager,
                 mMockINotificationManager,
                 mOnUserInteractionCallback,
                 TEST_PACKAGE_NAME,
@@ -1009,7 +1059,8 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler, null, Optional.of(mBubblesManager));
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
 
         mNotificationInfo.findViewById(R.id.default_behavior).performClick();
         mNotificationInfo.findViewById(R.id.done).performClick();
@@ -1032,6 +1083,7 @@
                 -1,
                 mShortcutManager,
                 mMockPackageManager,
+                mPeopleSpaceWidgetManager,
                 mMockINotificationManager,
                 mOnUserInteractionCallback,
                 TEST_PACKAGE_NAME,
@@ -1045,7 +1097,8 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler, null, Optional.of(mBubblesManager));
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
 
         View silence = mNotificationInfo.findViewById(R.id.silence);
         silence.performClick();
@@ -1067,6 +1120,7 @@
                 -1,
                 mShortcutManager,
                 mMockPackageManager,
+                mPeopleSpaceWidgetManager,
                 mMockINotificationManager,
                 mOnUserInteractionCallback,
                 TEST_PACKAGE_NAME,
@@ -1080,7 +1134,8 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler, null, Optional.of(mBubblesManager));
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
 
         verify(mMockINotificationManager, times(1)).createConversationNotificationChannelForPackage(
                 anyString(), anyInt(), any(), eq(CONVERSATION_ID));
@@ -1093,6 +1148,7 @@
                 -1,
                 mShortcutManager,
                 mMockPackageManager,
+                mPeopleSpaceWidgetManager,
                 mMockINotificationManager,
                 mOnUserInteractionCallback,
                 TEST_PACKAGE_NAME,
@@ -1106,7 +1162,8 @@
                 mBuilderProvider,
                 true,
                 mTestHandler,
-                mTestHandler, null, Optional.of(mBubblesManager));
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
 
         verify(mMockINotificationManager, never()).createConversationNotificationChannelForPackage(
                 anyString(), anyInt(), any(), eq(CONVERSATION_ID));
@@ -1115,7 +1172,7 @@
     @Test
     public void testSelectPriorityPresentsOnboarding_firstTime() {
         // GIVEN pref is false
-        Prefs.putBoolean(mContext, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING, false);
+        Prefs.putBoolean(mContext, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING_IN_S, false);
 
         // GIVEN the priority onboarding screen is present
         PriorityOnboardingDialogController.Builder b =
@@ -1129,6 +1186,7 @@
                 -1,
                 mShortcutManager,
                 mMockPackageManager,
+                mPeopleSpaceWidgetManager,
                 mMockINotificationManager,
                 mOnUserInteractionCallback,
                 TEST_PACKAGE_NAME,
@@ -1142,7 +1200,8 @@
                 () -> b,
                 true,
                 mTestHandler,
-                mTestHandler, null, Optional.of(mBubblesManager));
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
 
         // WHEN user clicks "priority"
         mNotificationInfo.setSelectedAction(NotificationConversationInfo.ACTION_FAVORITE);
@@ -1158,7 +1217,7 @@
     @Test
     public void testSelectPriorityDoesNotShowOnboarding_secondTime() {
         //WHEN pref is true
-        Prefs.putBoolean(mContext, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING, true);
+        Prefs.putBoolean(mContext, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING_IN_S, true);
 
         PriorityOnboardingDialogController.Builder b =
                 mock(PriorityOnboardingDialogController.Builder.class, Answers.RETURNS_SELF);
@@ -1170,6 +1229,7 @@
                 -1,
                 mShortcutManager,
                 mMockPackageManager,
+                mPeopleSpaceWidgetManager,
                 mMockINotificationManager,
                 mOnUserInteractionCallback,
                 TEST_PACKAGE_NAME,
@@ -1183,12 +1243,128 @@
                 () -> b,
                 true,
                 mTestHandler,
-                mTestHandler, null, Optional.of(mBubblesManager));
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
+
+        // WHEN user clicks "priority"
+        mNotificationInfo.setSelectedAction(NotificationConversationInfo.ACTION_FAVORITE);
+        verify(controller, never()).show();
+
+        // and then done
+        mNotificationInfo.findViewById(R.id.done).performClick();
+
+        // THEN the user is presented with the priority onboarding screen
+        verify(controller, never()).show();
+    }
+
+    @Test
+    public void testSelectPriorityRequestsPinPeopleTile() {
+        //WHEN pref is true and channel is default importance
+        Prefs.putBoolean(mContext, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING_IN_S, true);
+        mNotificationChannel.setImportantConversation(false);
+        mNotificationInfo.bindNotification(
+                -1,
+                mShortcutManager,
+                mMockPackageManager,
+                mPeopleSpaceWidgetManager,
+                mMockINotificationManager,
+                mOnUserInteractionCallback,
+                TEST_PACKAGE_NAME,
+                mNotificationChannel,
+                mEntry,
+                mBubbleMetadata,
+                null,
+                null,
+                mIconFactory,
+                mContext,
+                mBuilderProvider,
+                true,
+                mTestHandler,
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
 
         // WHEN user clicks "priority"
         mNotificationInfo.setSelectedAction(NotificationConversationInfo.ACTION_FAVORITE);
 
-        // THEN the user is presented with the priority onboarding screen
-        verify(controller, never()).show();
+        // and then done
+        mNotificationInfo.findViewById(R.id.done).performClick();
+
+        // THEN the user is presented with the People Tile pinning request
+        verify(mPeopleSpaceWidgetManager, times(1)).requestPinAppWidget(any());
+    }
+
+    @Test
+    public void testSelectDefaultDoesNotRequestPinPeopleTile() {
+        //WHEN pref is true
+        Prefs.putBoolean(mContext, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING_IN_S, true);
+
+        mNotificationInfo.bindNotification(
+                -1,
+                mShortcutManager,
+                mMockPackageManager,
+                mPeopleSpaceWidgetManager,
+                mMockINotificationManager,
+                mOnUserInteractionCallback,
+                TEST_PACKAGE_NAME,
+                mNotificationChannel,
+                mEntry,
+                mBubbleMetadata,
+                null,
+                null,
+                mIconFactory,
+                mContext,
+                mBuilderProvider,
+                true,
+                mTestHandler,
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
+
+        // WHEN user clicks "default"
+        mNotificationInfo.setSelectedAction(NotificationConversationInfo.ACTION_DEFAULT);
+
+        // and then done
+        mNotificationInfo.findViewById(R.id.done).performClick();
+
+        // THEN the user is not presented with the People Tile pinning request
+        verify(mPeopleSpaceWidgetManager, never()).requestPinAppWidget(mShortcutInfo);
+    }
+
+    @Test
+    public void testSelectPriority_AlreadyPriority_DoesNotRequestPinPeopleTile() {
+        //WHEN pref is true and channel is priority
+        Prefs.putBoolean(mContext, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING_IN_S, true);
+        mConversationChannel.setOriginalImportance(IMPORTANCE_HIGH);
+        mConversationChannel.setImportance(IMPORTANCE_HIGH);
+        mConversationChannel.setImportantConversation(true);
+
+        mNotificationInfo.bindNotification(
+                -1,
+                mShortcutManager,
+                mMockPackageManager,
+                mPeopleSpaceWidgetManager,
+                mMockINotificationManager,
+                mOnUserInteractionCallback,
+                TEST_PACKAGE_NAME,
+                mNotificationChannel,
+                mEntry,
+                mBubbleMetadata,
+                null,
+                null,
+                mIconFactory,
+                mContext,
+                mBuilderProvider,
+                true,
+                mTestHandler,
+                mTestHandler, null, Optional.of(mBubblesManager),
+                mShadeController);
+
+        // WHEN user clicks "priority"
+        mNotificationInfo.setSelectedAction(NotificationConversationInfo.ACTION_FAVORITE);
+
+        // and then done
+        mNotificationInfo.findViewById(R.id.done).performClick();
+
+        // THEN the user is not presented with the People Tile pinning request
+        verify(mPeopleSpaceWidgetManager, never()).requestPinAppWidget(mShortcutInfo);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index 458a058..18481bca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -67,17 +67,20 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.testing.UiEventLoggerFake;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.settings.UserContextProvider;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.notification.AssistantFeedbackController;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.wmshell.BubblesManager;
@@ -126,12 +129,15 @@
     @Mock private AccessibilityManager mAccessibilityManager;
     @Mock private HighPriorityProvider mHighPriorityProvider;
     @Mock private INotificationManager mINotificationManager;
+    @Mock private NotificationEntryManager mNotificationEntryManager;
     @Mock private LauncherApps mLauncherApps;
     @Mock private ShortcutManager mShortcutManager;
     @Mock private ChannelEditorDialogController mChannelEditorDialogController;
     @Mock private PeopleNotificationIdentifier mPeopleNotificationIdentifier;
     @Mock private UserContextProvider mContextTracker;
     @Mock private BubblesManager mBubblesManager;
+    @Mock private ShadeController mShadeController;
+    @Mock private PeopleSpaceWidgetManager mPeopleSpaceWidgetManager;
     @Mock(answer = Answers.RETURNS_SELF)
     private PriorityOnboardingDialogController.Builder mBuilder;
     private Provider<PriorityOnboardingDialogController.Builder> mProvider = () -> mBuilder;
@@ -154,10 +160,10 @@
 
         mGutsManager = new NotificationGutsManager(mContext,
                 () -> mStatusBar, mHandler, mHandler, mAccessibilityManager, mHighPriorityProvider,
-                mINotificationManager, mLauncherApps, mShortcutManager,
-                mChannelEditorDialogController, mContextTracker, mProvider,
-                mAssistantFeedbackController, Optional.of(mBubblesManager),
-                new UiEventLoggerFake(), mOnUserInteractionCallback);
+                mINotificationManager, mNotificationEntryManager, mPeopleSpaceWidgetManager,
+                mLauncherApps, mShortcutManager, mChannelEditorDialogController, mContextTracker,
+                mProvider, mAssistantFeedbackController, Optional.of(mBubblesManager),
+                new UiEventLoggerFake(), mOnUserInteractionCallback, mShadeController);
         mGutsManager.setUpWithPresenter(mPresenter, mNotificationListContainer,
                 mCheckSaveListener, mOnSettingsClickListener);
         mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index bc014ec..d9e9389 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -431,4 +431,14 @@
         mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
         assertThat(mBouncer.inTransit()).isFalse();
     }
+
+    @Test
+    public void testUpdateResources_delegatesToRootView() {
+        mBouncer.ensureView();
+        mBouncer.updateResources();
+
+        // This is mocked, so won't pick up on the call to updateResources via
+        // mKeyguardViewController.init(), only updateResources above.
+        verify(mKeyguardHostViewController).updateResources();
+    }
 }
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 ec5114e..91f3611 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
@@ -536,8 +536,7 @@
     @Test
     public void testCanCollapsePanelOnTouch_falseInDualPaneShade() {
         mStatusBarStateController.setState(SHADE);
-        when(mResources.getBoolean(R.bool.config_use_split_notification_shade)).thenReturn(true);
-        when(mFeatureFlags.isTwoColumnNotificationShadeEnabled()).thenReturn(true);
+        enableSplitShade();
         mNotificationPanelViewController.setQsExpanded(true);
 
         assertThat(mNotificationPanelViewController.canCollapsePanelOnTouch()).isFalse();
@@ -562,6 +561,7 @@
     private void enableSplitShade() {
         when(mResources.getBoolean(R.bool.config_use_split_notification_shade)).thenReturn(true);
         when(mFeatureFlags.isTwoColumnNotificationShadeEnabled()).thenReturn(true);
+        mNotificationPanelViewController.updateResources();
     }
 
     private void onTouchEvent(MotionEvent ev) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 83030ec..45b7917 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -276,4 +276,11 @@
         verify(action).onDismiss();
         verify(cancelAction, never()).run();
     }
+
+    @Test
+    public void testUpdateResources_delegatesToBouncer() {
+        mStatusBarKeyguardViewManager.updateResources();
+
+        verify(mBouncer).updateResources();
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 253460d..781cde6c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -78,6 +78,7 @@
 import com.android.systemui.InitController;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.classifier.FalsingCollectorFake;
@@ -112,6 +113,7 @@
 import com.android.systemui.statusbar.StatusBarStateControllerImpl;
 import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.charging.WiredChargingRippleController;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -210,6 +212,7 @@
     @Mock private NotificationGutsManager mNotificationGutsManager;
     @Mock private NotificationMediaManager mNotificationMediaManager;
     @Mock private NavigationBarController mNavigationBarController;
+    @Mock private AccessibilityFloatingMenuController mAccessibilityFloatingMenuController;
     @Mock private BypassHeadsUpNotifier mBypassHeadsUpNotifier;
     @Mock private SysuiColorExtractor mColorExtractor;
     @Mock private ColorExtractor.GradientColors mGradientColors;
@@ -259,6 +262,7 @@
     @Mock private DemoModeController mDemoModeController;
     @Mock private Lazy<NotificationShadeDepthController> mNotificationShadeDepthControllerLazy;
     @Mock private BrightnessSlider.Factory mBrightnessSliderFactory;
+    @Mock private WiredChargingRippleController mWiredChargingRippleController;
     @Mock private FeatureFlags mFeatureFlags;
     private ShadeController mShadeController;
     private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
@@ -385,6 +389,7 @@
                 mVisualStabilityManager,
                 mDeviceProvisionedController,
                 mNavigationBarController,
+                mAccessibilityFloatingMenuController,
                 () -> mAssistManager,
                 configurationController,
                 mNotificationShadeWindowController,
@@ -421,6 +426,7 @@
                 mStatusBarTouchableRegionManager,
                 mNotificationIconAreaController,
                 mBrightnessSliderFactory,
+                mWiredChargingRippleController,
                 mFeatureFlags);
 
         when(mNotificationShadeWindowView.findViewById(R.id.lock_icon_container)).thenReturn(
@@ -884,6 +890,13 @@
         verify(mDozeServiceHost).setDozeSuppressed(false);
     }
 
+    @Test
+    public void testUpdateResources_updatesBouncer() {
+        mStatusBar.updateResources();
+
+        verify(mStatusBarKeyguardViewManager).updateResources();
+    }
+
     public static class TestableNotificationInterruptStateProviderImpl extends
             NotificationInterruptStateProviderImpl {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java
index 203ece9..8ad6271 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java
@@ -66,7 +66,11 @@
     }
 
     @Override
-    public void setCallIndicatorIcons(String slot, List<CallIndicatorIconState> states) {
+    public void setCallStrengthIcons(String slot, List<CallIndicatorIconState> states) {
+    }
+
+    @Override
+    public void setNoCallingIcons(String slot, List<CallIndicatorIconState> states) {
     }
 
     @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/SyncExecutor.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/SyncExecutor.java
index d40eecf..6b68946 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/SyncExecutor.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/SyncExecutor.java
@@ -34,10 +34,6 @@
     }
 
     @Override
-    public void removeAllCallbacks() {
-    }
-
-    @Override
     public void removeCallbacks(Runnable runnable) {
     }
 
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index 5dd271c..f06a940 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -340,5 +340,9 @@
     // Notify the user that window magnification is available.
     // package: android
     NOTE_A11Y_WINDOW_MAGNIFICATION_FEATURE = 1004;
+
+    // Notify the user that some accessibility service has view and control permissions.
+    // package: android
+    NOTE_A11Y_VIEW_AND_CONTROL_ACCESS = 1005;
   }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index b3be044..e7ffb1a 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -309,13 +309,19 @@
      */
     public AccessibilityManagerService(Context context) {
         mContext = context;
-        mPowerManager =  (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+        mPowerManager = context.getSystemService(PowerManager.class);
         mWindowManagerService = LocalServices.getService(WindowManagerInternal.class);
         mA11yController = mWindowManagerService.getAccessibilityController();
         mMainHandler = new MainHandler(mContext.getMainLooper());
         mActivityTaskManagerService = LocalServices.getService(ActivityTaskManagerInternal.class);
         mPackageManager = mContext.getPackageManager();
-        mSecurityPolicy = new AccessibilitySecurityPolicy(mContext, this);
+        PolicyWarningUIController policyWarningUIController;
+        if (AccessibilitySecurityPolicy.POLICY_WARNING_ENABLED) {
+            policyWarningUIController = new PolicyWarningUIController(mMainHandler, context,
+                    new PolicyWarningUIController.NotificationController(context));
+        }
+        mSecurityPolicy = new AccessibilitySecurityPolicy(policyWarningUIController, mContext,
+                this);
         mA11yWindowManager = new AccessibilityWindowManager(mLock, mMainHandler,
                 mWindowManagerService, this, mSecurityPolicy, this);
         mA11yDisplayListener = new AccessibilityDisplayListener(mContext, mMainHandler);
@@ -351,6 +357,8 @@
         if (isA11yTracingEnabled()) {
             logTrace(LOG_TAG + ".onServiceInfoChangedLocked", "userState=" + userState);
         }
+        mSecurityPolicy.onBoundServicesChangedLocked(userState.mUserId,
+                userState.mBoundServices);
         scheduleNotifyClientsOfServicesStateChangeLocked(userState);
     }
 
@@ -1302,6 +1310,7 @@
             AccessibilityUserState userState = getCurrentUserStateLocked();
 
             readConfigurationForUserStateLocked(userState);
+            mSecurityPolicy.onSwitchUserLocked(mCurrentUserId, userState.mEnabledServices);
             // Even if reading did not yield change, we have to update
             // the state since the context in which the current user
             // state was used has changed since it was inactive.
@@ -3665,6 +3674,8 @@
                     }
                 } else if (mEnabledAccessibilityServicesUri.equals(uri)) {
                     if (readEnabledAccessibilityServicesLocked(userState)) {
+                        mSecurityPolicy.onEnabledServicesChangedLocked(userState.mUserId,
+                                userState.mEnabledServices);
                         userState.updateCrashedServicesIfNeededLocked();
                         onUserStateChangedLocked(userState);
                     }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
index bef6d3e..fd355d8 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
@@ -41,21 +41,19 @@
 
 import libcore.util.EmptyArray;
 
+import java.util.ArrayList;
+import java.util.Set;
+
 /**
  * This class provides APIs of accessibility security policies for accessibility manager
- * to grant accessibility capabilities or events access right to accessibility service.
+ * to grant accessibility capabilities or events access right to accessibility services. And also
+ * monitors the current bound accessibility services to prompt permission warnings for
+ * not accessibility-categorized ones.
  */
 public class AccessibilitySecurityPolicy {
     private static final int OWN_PROCESS_ID = android.os.Process.myPid();
     private static final String LOG_TAG = "AccessibilitySecurityPolicy";
 
-    private final Context mContext;
-    private final PackageManager mPackageManager;
-    private final UserManager mUserManager;
-    private final AppOpsManager mAppOpsManager;
-
-    private AppWidgetManagerInternal mAppWidgetService;
-
     private static final int KEEP_SOURCE_EVENT_TYPES = AccessibilityEvent.TYPE_VIEW_CLICKED
             | AccessibilityEvent.TYPE_VIEW_FOCUSED
             | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER
@@ -72,6 +70,8 @@
             | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED
             | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY;
 
+    public static final boolean POLICY_WARNING_ENABLED = true;
+
     /**
      * Methods that should find their way into separate modules, but are still in AMS
      * TODO (b/111889696): Refactoring UserState to AccessibilityUserManager.
@@ -84,19 +84,32 @@
         // TODO: Should include resolveProfileParentLocked, but that was already in SecurityPolicy
     }
 
+    private final Context mContext;
+    private final PackageManager mPackageManager;
+    private final UserManager mUserManager;
+    private final AppOpsManager mAppOpsManager;
     private final AccessibilityUserManager mAccessibilityUserManager;
+    private final PolicyWarningUIController mPolicyWarningUIController;
+    /** All bound accessibility services which don't belong to accessibility category. */
+    private final ArraySet<ComponentName> mNonA11yCategoryServices = new ArraySet<>();
+
+    private AppWidgetManagerInternal mAppWidgetService;
     private AccessibilityWindowManager mAccessibilityWindowManager;
+    private int mCurrentUserId = UserHandle.USER_NULL;
 
     /**
      * Constructor for AccessibilityManagerService.
      */
-    public AccessibilitySecurityPolicy(@NonNull Context context,
+    public AccessibilitySecurityPolicy(PolicyWarningUIController policyWarningUIController,
+            @NonNull Context context,
             @NonNull AccessibilityUserManager a11yUserManager) {
         mContext = context;
         mAccessibilityUserManager = a11yUserManager;
         mPackageManager = mContext.getPackageManager();
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+        mPolicyWarningUIController = policyWarningUIController;
+        mPolicyWarningUIController.setAccessibilityPolicyManager(this);
     }
 
     /**
@@ -568,4 +581,98 @@
                     + permission);
         }
     }
+
+    /**
+     * Called after a service was bound or unbound. Checks the current bound accessibility
+     * services and updates alarms.
+     *
+     * @param userId        The user id
+     * @param boundServices The bound services
+     */
+    public void onBoundServicesChangedLocked(int userId,
+            ArrayList<AccessibilityServiceConnection> boundServices) {
+        if (!POLICY_WARNING_ENABLED) {
+            return;
+        }
+        if (mAccessibilityUserManager.getCurrentUserIdLocked() != userId) {
+            return;
+        }
+
+        ArraySet<ComponentName> tempNonA11yCategoryServices = new ArraySet<>();
+        for (int i = 0; i < boundServices.size(); i++) {
+            final AccessibilityServiceInfo a11yServiceInfo = boundServices.get(
+                    i).getServiceInfo();
+            final ComponentName service = a11yServiceInfo.getComponentName().clone();
+            if (!isA11yCategoryService(a11yServiceInfo)) {
+                tempNonA11yCategoryServices.add(service);
+                if (mNonA11yCategoryServices.contains(service)) {
+                    mNonA11yCategoryServices.remove(service);
+                } else {
+                    mPolicyWarningUIController.onNonA11yCategoryServiceBound(userId, service);
+                }
+            }
+        }
+
+        for (int i = 0; i < mNonA11yCategoryServices.size(); i++) {
+            final ComponentName service = mNonA11yCategoryServices.valueAt(i);
+            mPolicyWarningUIController.onNonA11yCategoryServiceUnbound(userId, service);
+        }
+        mNonA11yCategoryServices.clear();
+        mNonA11yCategoryServices.addAll(tempNonA11yCategoryServices);
+    }
+
+    /**
+     * Called after switching to another user. Resets data and cancels old alarms after
+     * switching to another user.
+     *
+     * @param userId          The user id
+     * @param enabledServices The enabled services
+     */
+    public void onSwitchUserLocked(int userId, Set<ComponentName> enabledServices) {
+        if (!POLICY_WARNING_ENABLED) {
+            return;
+        }
+        if (mCurrentUserId == userId) {
+            return;
+        }
+
+        mPolicyWarningUIController.onSwitchUserLocked(userId, enabledServices);
+
+        for (int i = 0; i < mNonA11yCategoryServices.size(); i++) {
+            mPolicyWarningUIController.onNonA11yCategoryServiceUnbound(mCurrentUserId,
+                    mNonA11yCategoryServices.valueAt(i));
+        }
+        mNonA11yCategoryServices.clear();
+        mCurrentUserId = userId;
+    }
+
+    /**
+     * Called after the enabled accessibility services changed.
+     *
+     * @param userId          The user id
+     * @param enabledServices The enabled services
+     */
+    public void onEnabledServicesChangedLocked(int userId,
+            Set<ComponentName> enabledServices) {
+        if (!POLICY_WARNING_ENABLED) {
+            return;
+        }
+        if (mAccessibilityUserManager.getCurrentUserIdLocked() != userId) {
+            return;
+        }
+
+        mPolicyWarningUIController.onEnabledServicesChangedLocked(userId, enabledServices);
+    }
+
+    /**
+     * Identifies whether the accessibility service is true and designed for accessibility. An
+     * accessibility service is considered as accessibility category if
+     * {@link AccessibilityServiceInfo#isAccessibilityTool} is true.
+     *
+     * @param serviceInfo The accessibility service's serviceInfo.
+     * @return Returns true if it is a true accessibility service.
+     */
+    public boolean isA11yCategoryService(AccessibilityServiceInfo serviceInfo) {
+        return serviceInfo.isAccessibilityTool();
+    }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/PolicyWarningUIController.java b/services/accessibility/java/com/android/server/accessibility/PolicyWarningUIController.java
new file mode 100644
index 0000000..ea3e650
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/PolicyWarningUIController.java
@@ -0,0 +1,370 @@
+/*
+ * 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;
+
+import static android.app.AlarmManager.RTC_WAKEUP;
+
+import static com.android.internal.messages.nano.SystemMessageProto.SystemMessage.NOTE_A11Y_VIEW_AND_CONTROL_ACCESS;
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
+import android.Manifest;
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.annotation.MainThread;
+import android.annotation.NonNull;
+import android.app.ActivityOptions;
+import android.app.AlarmManager;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.StatusBarManager;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.view.accessibility.AccessibilityManager;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.notification.SystemNotificationChannels;
+import com.android.internal.util.ImageUtils;
+
+import java.util.Calendar;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * The class handles permission warning notifications for not accessibility-categorized
+ * accessibility services from {@link AccessibilitySecurityPolicy}. And also maintains the setting
+ * {@link Settings.Secure#NOTIFIED_NON_ACCESSIBILITY_CATEGORY_SERVICES} in order not to
+ * resend notifications to the same service.
+ */
+public class PolicyWarningUIController {
+    private static final String TAG = PolicyWarningUIController.class.getSimpleName();
+    @VisibleForTesting
+    protected static final String ACTION_SEND_NOTIFICATION = TAG + ".ACTION_SEND_NOTIFICATION";
+    @VisibleForTesting
+    protected static final String ACTION_A11Y_SETTINGS = TAG + ".ACTION_A11Y_SETTINGS";
+    @VisibleForTesting
+    protected static final String ACTION_DISMISS_NOTIFICATION =
+            TAG + ".ACTION_DISMISS_NOTIFICATION";
+    private static final int SEND_NOTIFICATION_DELAY_HOURS = 24;
+
+    /** Current enabled accessibility services. */
+    private final ArraySet<ComponentName> mEnabledA11yServices = new ArraySet<>();
+
+    private final Handler mMainHandler;
+    private final AlarmManager mAlarmManager;
+    private final Context mContext;
+    private final NotificationController mNotificationController;
+
+    public PolicyWarningUIController(@NonNull Handler handler, @NonNull Context context,
+            NotificationController notificationController) {
+        mMainHandler = handler;
+        mContext = context;
+        mNotificationController = notificationController;
+        mAlarmManager = mContext.getSystemService(AlarmManager.class);
+        final IntentFilter filter = new IntentFilter();
+        filter.addAction(ACTION_SEND_NOTIFICATION);
+        filter.addAction(ACTION_A11Y_SETTINGS);
+        filter.addAction(ACTION_DISMISS_NOTIFICATION);
+        mContext.registerReceiver(mNotificationController, filter,
+                Manifest.permission.MANAGE_ACCESSIBILITY, mMainHandler);
+
+    }
+
+    protected void setAccessibilityPolicyManager(
+            AccessibilitySecurityPolicy accessibilitySecurityPolicy) {
+        mNotificationController.setAccessibilityPolicyManager(accessibilitySecurityPolicy);
+    }
+
+    /**
+     * Updates enabled accessibility services and notified accessibility services after switching
+     * to another user.
+     *
+     * @param enabledServices The current enabled services
+     */
+    public void onSwitchUserLocked(int userId, Set<ComponentName> enabledServices) {
+        mEnabledA11yServices.clear();
+        mEnabledA11yServices.addAll(enabledServices);
+        mMainHandler.sendMessage(obtainMessage(mNotificationController::onSwitchUser, userId));
+    }
+
+    /**
+     * Computes the newly disabled services and removes its record from the setting
+     * {@link Settings.Secure#NOTIFIED_NON_ACCESSIBILITY_CATEGORY_SERVICES} after detecting the
+     * setting {@link Settings.Secure#ENABLED_ACCESSIBILITY_SERVICES} changed.
+     *
+     * @param userId          The user id
+     * @param enabledServices The enabled services
+     */
+    public void onEnabledServicesChangedLocked(int userId,
+            Set<ComponentName> enabledServices) {
+        final ArraySet<ComponentName> disabledServices = new ArraySet<>(mEnabledA11yServices);
+        disabledServices.removeAll(enabledServices);
+        mEnabledA11yServices.clear();
+        mEnabledA11yServices.addAll(enabledServices);
+        mMainHandler.sendMessage(
+                obtainMessage(mNotificationController::onServicesDisabled, userId,
+                        disabledServices));
+    }
+
+    /**
+     * Called when the target service is bound. Sets an 24 hours alarm to the service which is not
+     * notified yet to execute action {@code ACTION_SEND_NOTIFICATION}.
+     *
+     * @param userId  The user id
+     * @param service The service's component name
+     */
+    public void onNonA11yCategoryServiceBound(int userId, ComponentName service) {
+        mMainHandler.sendMessage(obtainMessage(this::setAlarm, userId, service));
+    }
+
+    /**
+     * Called when the target service is unbound. Cancels the old alarm with intent action
+     * {@code ACTION_SEND_NOTIFICATION} from the service.
+     *
+     * @param userId  The user id
+     * @param service The service's component name
+     */
+    public void onNonA11yCategoryServiceUnbound(int userId, ComponentName service) {
+        mMainHandler.sendMessage(obtainMessage(this::cancelAlarm, userId, service));
+    }
+
+    private void setAlarm(int userId, ComponentName service) {
+        final Calendar cal = Calendar.getInstance();
+        cal.add(Calendar.HOUR, SEND_NOTIFICATION_DELAY_HOURS);
+        mAlarmManager.set(RTC_WAKEUP, cal.getTimeInMillis(),
+                createPendingIntent(mContext, userId, ACTION_SEND_NOTIFICATION,
+                        service.flattenToShortString()));
+    }
+
+    private void cancelAlarm(int userId, ComponentName service) {
+        mAlarmManager.cancel(
+                createPendingIntent(mContext, userId, ACTION_SEND_NOTIFICATION,
+                        service.flattenToShortString()));
+    }
+
+    protected static PendingIntent createPendingIntent(Context context, int userId, String action,
+            String serviceComponentName) {
+        final Intent intent = new Intent(action);
+        intent.setPackage(context.getPackageName())
+                .setIdentifier(serviceComponentName)
+                .putExtra(Intent.EXTRA_USER_ID, userId);
+        return PendingIntent.getBroadcast(context, 0, intent,
+                PendingIntent.FLAG_IMMUTABLE);
+    }
+
+    /** A sub class to handle notifications and settings on the main thread. */
+    @MainThread
+    public static class NotificationController extends BroadcastReceiver {
+        private static final char RECORD_SEPARATOR = ':';
+
+        /** All accessibility services which are notified to the user by the policy warning rule. */
+        private final ArraySet<ComponentName> mNotifiedA11yServices = new ArraySet<>();
+        private final NotificationManager mNotificationManager;
+        private final Context mContext;
+
+        private int mCurrentUserId;
+        private AccessibilitySecurityPolicy mAccessibilitySecurityPolicy;
+
+        public NotificationController(Context context) {
+            mContext = context;
+            mNotificationManager = mContext.getSystemService(NotificationManager.class);
+        }
+
+        protected void setAccessibilityPolicyManager(
+                AccessibilitySecurityPolicy accessibilitySecurityPolicy) {
+            mAccessibilitySecurityPolicy = accessibilitySecurityPolicy;
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            final String service = intent.getIdentifier();
+            final ComponentName componentName = ComponentName.unflattenFromString(service);
+            if (TextUtils.isEmpty(action) || TextUtils.isEmpty(service)
+                    || componentName == null) {
+                return;
+            }
+            final int userId = intent.getIntExtra(Intent.EXTRA_USER_ID, UserHandle.USER_SYSTEM);
+            if (ACTION_SEND_NOTIFICATION.equals(action)) {
+                trySendNotification(userId, componentName);
+            } else if (ACTION_A11Y_SETTINGS.equals(action)) {
+                launchSettings(userId, componentName);
+                mNotificationManager.cancel(service, NOTE_A11Y_VIEW_AND_CONTROL_ACCESS);
+                onNotificationCanceled(userId, componentName);
+            } else if (ACTION_DISMISS_NOTIFICATION.equals(action)) {
+                onNotificationCanceled(userId, componentName);
+            }
+        }
+
+        protected void onSwitchUser(int userId) {
+            mCurrentUserId = userId;
+            mNotifiedA11yServices.clear();
+            mNotifiedA11yServices.addAll(readNotifiedServiceList(userId));
+        }
+
+        protected void onServicesDisabled(int userId,
+                ArraySet<ComponentName> disabledServices) {
+            if (mNotifiedA11yServices.removeAll(disabledServices)) {
+                writeNotifiedServiceList(userId, mNotifiedA11yServices);
+            }
+        }
+
+        private void trySendNotification(int userId, ComponentName componentName) {
+            if (!AccessibilitySecurityPolicy.POLICY_WARNING_ENABLED) {
+                return;
+            }
+            if (userId != mCurrentUserId) {
+                return;
+            }
+
+            List<AccessibilityServiceInfo> enabledServiceInfos = getEnabledServiceInfos();
+            for (int i = 0; i < enabledServiceInfos.size(); i++) {
+                final AccessibilityServiceInfo a11yServiceInfo = enabledServiceInfos.get(i);
+                if (componentName.flattenToShortString().equals(
+                        a11yServiceInfo.getComponentName().flattenToShortString())) {
+                    if (!mAccessibilitySecurityPolicy.isA11yCategoryService(a11yServiceInfo)
+                            && !mNotifiedA11yServices.contains(componentName)) {
+                        final CharSequence displayName =
+                                a11yServiceInfo.getResolveInfo().serviceInfo.loadLabel(
+                                        mContext.getPackageManager());
+                        final Drawable drawable = a11yServiceInfo.getResolveInfo().loadIcon(
+                                mContext.getPackageManager());
+                        final int size = mContext.getResources().getDimensionPixelSize(
+                                android.R.dimen.app_icon_size);
+                        sendNotification(userId, componentName.flattenToShortString(),
+                                displayName,
+                                ImageUtils.buildScaledBitmap(drawable, size, size));
+                    }
+                    break;
+                }
+            }
+        }
+
+        private void launchSettings(int userId, ComponentName componentName) {
+            if (userId != mCurrentUserId) {
+                return;
+            }
+            final Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_DETAILS_SETTINGS);
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+            intent.putExtra(Intent.EXTRA_COMPONENT_NAME, componentName.flattenToShortString());
+            final Bundle bundle = ActivityOptions.makeBasic().setLaunchDisplayId(
+                    mContext.getDisplayId()).toBundle();
+            mContext.startActivityAsUser(intent, bundle, UserHandle.of(userId));
+            mContext.getSystemService(StatusBarManager.class).collapsePanels();
+        }
+
+        protected void onNotificationCanceled(int userId, ComponentName componentName) {
+            if (userId != mCurrentUserId) {
+                return;
+            }
+
+            if (mNotifiedA11yServices.add(componentName)) {
+                writeNotifiedServiceList(userId, mNotifiedA11yServices);
+            }
+        }
+
+        private void sendNotification(int userId, String serviceComponentName, CharSequence name,
+                Bitmap bitmap) {
+            final Notification.Builder notificationBuilder = new Notification.Builder(mContext,
+                    SystemNotificationChannels.ACCESSIBILITY_SECURITY_POLICY);
+            notificationBuilder.setSmallIcon(R.drawable.ic_accessibility_24dp)
+                    .setContentTitle(
+                            mContext.getString(R.string.view_and_control_notification_title))
+                    .setContentText(
+                            mContext.getString(R.string.view_and_control_notification_content,
+                                    name))
+                    .setStyle(new Notification.BigTextStyle()
+                            .bigText(
+                                    mContext.getString(
+                                            R.string.view_and_control_notification_content,
+                                            name)))
+                    .setTicker(mContext.getString(R.string.view_and_control_notification_title))
+                    .setOnlyAlertOnce(true)
+                    .setDeleteIntent(
+                            createPendingIntent(mContext, userId, ACTION_DISMISS_NOTIFICATION,
+                                    serviceComponentName))
+                    .setContentIntent(
+                            createPendingIntent(mContext, userId, ACTION_A11Y_SETTINGS,
+                                    serviceComponentName));
+            if (bitmap != null) {
+                notificationBuilder.setLargeIcon(bitmap);
+            }
+            mNotificationManager.notify(serviceComponentName, NOTE_A11Y_VIEW_AND_CONTROL_ACCESS,
+                    notificationBuilder.build());
+        }
+
+        private ArraySet<ComponentName> readNotifiedServiceList(int userId) {
+            final String notifiedServiceSetting = Settings.Secure.getStringForUser(
+                    mContext.getContentResolver(),
+                    Settings.Secure.NOTIFIED_NON_ACCESSIBILITY_CATEGORY_SERVICES,
+                    userId);
+            if (TextUtils.isEmpty(notifiedServiceSetting)) {
+                return new ArraySet<>();
+            }
+
+            final TextUtils.StringSplitter componentNameSplitter =
+                    new TextUtils.SimpleStringSplitter(RECORD_SEPARATOR);
+            componentNameSplitter.setString(notifiedServiceSetting);
+
+            final ArraySet<ComponentName> notifiedServices = new ArraySet<>();
+            final Iterator<String> it = componentNameSplitter.iterator();
+            while (it.hasNext()) {
+                final String componentNameString = it.next();
+                final ComponentName notifiedService = ComponentName.unflattenFromString(
+                        componentNameString);
+                if (notifiedService != null) {
+                    notifiedServices.add(notifiedService);
+                }
+            }
+            return notifiedServices;
+        }
+
+        private void writeNotifiedServiceList(int userId, ArraySet<ComponentName> services) {
+            StringBuilder notifiedServicesBuilder = new StringBuilder();
+            for (int i = 0; i < services.size(); i++) {
+                if (i > 0) {
+                    notifiedServicesBuilder.append(RECORD_SEPARATOR);
+                }
+                final ComponentName notifiedService = services.valueAt(i);
+                notifiedServicesBuilder.append(notifiedService.flattenToShortString());
+            }
+            Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                    Settings.Secure.NOTIFIED_NON_ACCESSIBILITY_CATEGORY_SERVICES,
+                    notifiedServicesBuilder.toString(), userId);
+        }
+
+        @VisibleForTesting
+        protected List<AccessibilityServiceInfo> getEnabledServiceInfos() {
+            final AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(
+                    mContext);
+            return accessibilityManager.getEnabledAccessibilityServiceList(
+                    AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
+        }
+    }
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
index 3d07da5..5b74cbd 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
@@ -114,6 +114,8 @@
         private boolean mUnregisterPending;
         private boolean mDeleteAfterUnregister;
 
+        private boolean mForceShowMagnifiableBounds;
+
         private final int mDisplayId;
 
         private static final int INVALID_ID = -1;
@@ -420,12 +422,18 @@
         @GuardedBy("mLock")
         void setForceShowMagnifiableBounds(boolean show) {
             if (mRegistered) {
+                mForceShowMagnifiableBounds = show;
                 mControllerCtx.getWindowManager().setForceShowMagnifiableBounds(
                         mDisplayId, show);
             }
         }
 
         @GuardedBy("mLock")
+        boolean isForceShowMagnifiableBounds() {
+            return mRegistered && mForceShowMagnifiableBounds;
+        }
+
+        @GuardedBy("mLock")
         boolean reset(boolean animate) {
             return reset(transformToStubCallback(animate));
         }
@@ -442,6 +450,7 @@
                 onMagnificationChangedLocked();
             }
             mIdOfLastServiceToMagnify = INVALID_ID;
+            mForceShowMagnifiableBounds = false;
             sendSpecToAnimation(spec, animationCallback);
             return changed;
         }
@@ -1158,6 +1167,21 @@
         }
     }
 
+    /**
+     * Returns {@code true} if the magnifiable regions of the display is forced to be shown.
+     *
+     * @param displayId The logical display id.
+     */
+    public boolean isForceShowMagnifiableBounds(int displayId) {
+        synchronized (mLock) {
+            final DisplayMagnification display = mDisplays.get(displayId);
+            if (display == null) {
+                return false;
+            }
+            return display.isForceShowMagnifiableBounds();
+        }
+    }
+
     private void onScreenTurnedOff() {
         final Message m = PooledLambda.obtainMessage(
                 FullScreenMagnificationController::resetAllIfNeeded, this, false);
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
index 17a7d39..2073c70 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
@@ -52,6 +52,9 @@
  *   <li> 4. {@link #onTripleTapped} updates magnification switch UI depending on magnification
  *   capabilities and magnification active state when triple-tap gesture is detected. </li>
  * </ol>
+ *
+ *  <b>Note</b>  Updates magnification switch UI when magnification mode transition
+ *  is done {@link DisableMagnificationCallback#onResult}.
  */
 public class MagnificationController implements WindowMagnificationManager.Callback,
         MagnificationGestureHandler.Callback,
@@ -358,7 +361,8 @@
         boolean isActivated = false;
         if (mode == ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN
                 && mFullScreenMagnificationController != null) {
-            isActivated = mFullScreenMagnificationController.isMagnifying(displayId);
+            isActivated = mFullScreenMagnificationController.isMagnifying(displayId)
+                    || mFullScreenMagnificationController.isForceShowMagnifiableBounds(displayId);
         } else if (mode == ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW
                 && mWindowMagnificationMgr != null) {
             isActivated = mWindowMagnificationMgr.isWindowMagnifierEnabled(displayId);
@@ -400,6 +404,7 @@
                     adjustCurrentCenterIfNeededLocked();
                     applyMagnificationModeLocked(mTargetMode);
                 }
+                updateMagnificationButton(mDisplayId, mTargetMode);
                 mTransitionCallBack.onResult(success);
             }
         }
@@ -424,6 +429,7 @@
                 }
                 setExpiredAndRemoveFromListLocked();
                 applyMagnificationModeLocked(mCurrentMode);
+                updateMagnificationButton(mDisplayId, mCurrentMode);
                 mTransitionCallBack.onResult(true);
             }
         }
diff --git a/services/api/Android.bp b/services/api/Android.bp
index b8ca548..bbc8c72 100644
--- a/services/api/Android.bp
+++ b/services/api/Android.bp
@@ -14,6 +14,12 @@
 
 package {
     default_visibility: ["//visibility:private"],
+    // 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 {
@@ -26,4 +32,4 @@
     name: "non-updatable-system-server-removed.txt",
     srcs: ["non-updatable-removed.txt"],
     visibility: ["//frameworks/base/api"],
-}
\ No newline at end of file
+}
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
index b15d07b..9d4c9eb 100644
--- a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
@@ -16,10 +16,13 @@
 
 package com.android.server.autofill.ui;
 
+import static android.view.inputmethod.InlineSuggestionInfo.TYPE_SUGGESTION;
+
 import static com.android.server.autofill.Helper.sDebug;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.IntentSender;
 import android.service.autofill.Dataset;
 import android.service.autofill.FillResponse;
 import android.service.autofill.InlinePresentation;
@@ -49,6 +52,9 @@
                 InlineSuggestionInfo.TYPE_ACTION, () -> uiCallback.authenticate(requestId,
                         AutofillManager.AUTHENTICATION_ID_DATASET_ID_UNDEFINED),
                 mergedInlinePresentation(inlineFillUiInfo.mInlineRequest, 0, inlineAuthentication),
+                createInlineSuggestionTooltip(inlineFillUiInfo.mInlineRequest,
+                        inlineFillUiInfo, InlineSuggestionInfo.SOURCE_AUTOFILL,
+                        response.getInlineTooltipPresentation()),
                 uiCallback);
     }
 
@@ -66,6 +72,8 @@
 
         final InlineSuggestionsRequest request = inlineFillUiInfo.mInlineRequest;
         SparseArray<Pair<Dataset, InlineSuggestion>> response = new SparseArray<>(datasets.size());
+
+        boolean hasTooltip = false;
         for (int datasetIndex = 0; datasetIndex < datasets.size(); datasetIndex++) {
             final Dataset dataset = datasets.get(datasetIndex);
             final int fieldIndex = dataset.getFieldIds().indexOf(inlineFillUiInfo.mFocusedId);
@@ -82,14 +90,25 @@
             }
 
             final String suggestionType =
-                    dataset.getAuthentication() == null ? InlineSuggestionInfo.TYPE_SUGGESTION
+                    dataset.getAuthentication() == null ? TYPE_SUGGESTION
                             : InlineSuggestionInfo.TYPE_ACTION;
             final int index = datasetIndex;
 
+            InlineSuggestion inlineSuggestionTooltip = null;
+            if (!hasTooltip) {
+                // Only available for first one inline suggestion tooltip.
+                inlineSuggestionTooltip = createInlineSuggestionTooltip(request,
+                        inlineFillUiInfo, suggestionSource,
+                        dataset.getFieldInlineTooltipPresentation(fieldIndex));
+                if (inlineSuggestionTooltip != null) {
+                    hasTooltip = true;
+                }
+            }
             InlineSuggestion inlineSuggestion = createInlineSuggestion(
                     inlineFillUiInfo, suggestionSource, suggestionType,
                     () -> uiCallback.autofill(dataset, index),
                     mergedInlinePresentation(request, datasetIndex, inlinePresentation),
+                    inlineSuggestionTooltip,
                     uiCallback);
             response.append(datasetIndex, Pair.create(dataset, inlineSuggestion));
         }
@@ -103,11 +122,13 @@
             @NonNull @InlineSuggestionInfo.Type String suggestionType,
             @NonNull Runnable onClickAction,
             @NonNull InlinePresentation inlinePresentation,
+            @Nullable InlineSuggestion tooltip,
             @NonNull InlineFillUi.InlineSuggestionUiCallback uiCallback) {
+
         final InlineSuggestionInfo inlineSuggestionInfo = new InlineSuggestionInfo(
                 inlinePresentation.getInlinePresentationSpec(), suggestionSource,
                 inlinePresentation.getAutofillHints(), suggestionType,
-                inlinePresentation.isPinned());
+                inlinePresentation.isPinned(), tooltip);
 
         return new InlineSuggestion(inlineSuggestionInfo,
                 createInlineContentProvider(inlineFillUiInfo, inlinePresentation,
@@ -135,6 +156,60 @@
                 inlinePresentation.isPinned());
     }
 
+    // TODO(182306770): creates new class instead of the InlineSuggestion.
+    private static InlineSuggestion createInlineSuggestionTooltip(
+            @NonNull InlineSuggestionsRequest request,
+            @NonNull InlineFillUi.InlineFillUiInfo inlineFillUiInfo,
+            String suggestionSource,
+            @NonNull InlinePresentation tooltipPresentation) {
+        if (tooltipPresentation == null) {
+            return null;
+        }
+
+        final InlinePresentationSpec spec = request.getInlineTooltipPresentationSpec();
+        InlinePresentationSpec mergedSpec;
+        if (spec == null) {
+            mergedSpec = tooltipPresentation.getInlinePresentationSpec();
+        } else {
+            mergedSpec = new InlinePresentationSpec.Builder(
+                    tooltipPresentation.getInlinePresentationSpec().getMinSize(),
+                    tooltipPresentation.getInlinePresentationSpec().getMaxSize()).setStyle(
+                    spec.getStyle()).build();
+        }
+
+        InlineFillUi.InlineSuggestionUiCallback uiCallback =
+                new InlineFillUi.InlineSuggestionUiCallback() {
+                    @Override
+                    public void autofill(Dataset dataset, int datasetIndex) {
+                        /* nothing */
+                    }
+
+                    @Override
+                    public void authenticate(int requestId, int datasetIndex) {
+                        /* nothing */
+                    }
+
+                    @Override
+                    public void startIntentSender(IntentSender intentSender) {
+                        /* nothing */
+                    }
+
+                    @Override
+                    public void onError() {
+                        Slog.w(TAG, "An error happened on the tooltip");
+                    }
+                };
+
+        InlinePresentation tooltipInline = new InlinePresentation(tooltipPresentation.getSlice(),
+                mergedSpec, false);
+        IInlineContentProvider tooltipContentProvider = createInlineContentProvider(
+                inlineFillUiInfo, tooltipInline, () -> { /* no operation */ }, uiCallback);
+        final InlineSuggestionInfo tooltipInlineSuggestionInfo = new InlineSuggestionInfo(
+                mergedSpec, suggestionSource, /* autofillHints */ null, TYPE_SUGGESTION,
+                        /* pinned */ false, /* tooltip */ null);
+        return new InlineSuggestion(tooltipInlineSuggestionInfo, tooltipContentProvider);
+    }
+
     private static IInlineContentProvider createInlineContentProvider(
             @NonNull InlineFillUi.InlineFillUiInfo inlineFillUiInfo,
             @NonNull InlinePresentation inlinePresentation, @Nullable Runnable onClickAction,
diff --git a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
index 602dc24..d0a8881 100644
--- a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
+++ b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
@@ -16,6 +16,8 @@
 
 package com.android.server.backup.restore;
 
+import static android.app.backup.BackupManager.OperationType;
+
 import static com.android.server.backup.BackupManagerService.DEBUG;
 import static com.android.server.backup.BackupManagerService.MORE_DEBUG;
 import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_SESSION_TIMEOUT;
@@ -24,6 +26,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.backup.BackupManager;
 import android.app.backup.IBackupManagerMonitor;
 import android.app.backup.IRestoreObserver;
 import android.app.backup.IRestoreSession;
@@ -51,6 +54,7 @@
  */
 public class ActiveRestoreSession extends IRestoreSession.Stub {
     private static final String TAG = "RestoreSession";
+    private static final String DEVICE_NAME_FOR_D2D_SET = "D2D";
 
     private final TransportManager mTransportManager;
     private final String mTransportName;
@@ -174,6 +178,7 @@
             for (int i = 0; i < mRestoreSets.length; i++) {
                 if (token == mRestoreSets[i].token) {
                     final long oldId = Binder.clearCallingIdentity();
+                    RestoreSet restoreSet = mRestoreSets[i];
                     try {
                         return sendRestoreToHandlerLocked(
                                 (transportClient, listener) ->
@@ -183,7 +188,7 @@
                                                 monitor,
                                                 token,
                                                 listener,
-                                                mBackupEligibilityRules),
+                                                getBackupEligibilityRules(restoreSet)),
                                 "RestoreSession.restoreAll()");
                     } finally {
                         Binder.restoreCallingIdentity(oldId);
@@ -266,6 +271,7 @@
             for (int i = 0; i < mRestoreSets.length; i++) {
                 if (token == mRestoreSets[i].token) {
                     final long oldId = Binder.clearCallingIdentity();
+                    RestoreSet restoreSet = mRestoreSets[i];
                     try {
                         return sendRestoreToHandlerLocked(
                                 (transportClient, listener) ->
@@ -277,7 +283,7 @@
                                                 packages,
                                                 /* isSystemRestore */ packages.length > 1,
                                                 listener,
-                                                mBackupEligibilityRules),
+                                                getBackupEligibilityRules(restoreSet)),
                                 "RestoreSession.restorePackages(" + packages.length + " packages)");
                     } finally {
                         Binder.restoreCallingIdentity(oldId);
@@ -290,6 +296,14 @@
         return -1;
     }
 
+    private BackupEligibilityRules getBackupEligibilityRules(RestoreSet restoreSet) {
+        // TODO(b/182986784): Remove device name comparison once a designated field for operation
+        //  type is added to RestoreSet object.
+        int operationType = DEVICE_NAME_FOR_D2D_SET.equals(restoreSet.device)
+                ? OperationType.MIGRATION : OperationType.BACKUP;
+        return mBackupManagerService.getEligibilityRulesForOperation(operationType);
+    }
+
     public synchronized int restorePackage(String packageName, IRestoreObserver observer,
             IBackupManagerMonitor monitor) {
         if (DEBUG) {
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 92af080..9ac93d9 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -1078,6 +1078,7 @@
         Date lastSeen = mDevicesLastNearby.get(address);
         if (isDeviceDisappeared(lastSeen)) {
             onDeviceDisappeared(address);
+            unscheduleTriggerDeviceDisappearedRunnable(address);
         }
     }
 
@@ -1213,7 +1214,18 @@
         @Override
         public void run() {
             Slog.d(LOG_TAG, "TriggerDeviceDisappearedRunnable.run(address = " + mAddress + ")");
-            onDeviceDisappeared(mAddress);
+            if (!mCurrentlyConnectedDevices.contains(mAddress)) {
+                onDeviceDisappeared(mAddress);
+            }
+        }
+    }
+
+    private void unscheduleTriggerDeviceDisappearedRunnable(String address) {
+        Runnable r = mTriggerDeviceDisappearedRunnables.get(address);
+        if (r != null) {
+            Slog.d(LOG_TAG,
+                    "unscheduling TriggerDeviceDisappearedRunnable(address = " + address + ")");
+            mMainHandler.removeCallbacks(r);
         }
     }
 
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index f4a8ccd..25ea12b 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -58,6 +58,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.ParcelFileDescriptor;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
@@ -69,7 +70,6 @@
 import android.service.contentcapture.ActivityEvent.ActivityEventType;
 import android.service.contentcapture.IDataShareCallback;
 import android.service.contentcapture.IDataShareReadAdapter;
-import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.LocalLog;
 import android.util.Pair;
@@ -174,6 +174,9 @@
     @GuardedBy("mLock")
     private final Set<String> mPackagesWithShareRequests = new HashSet<>();
 
+    private final RemoteCallbackList<IContentCaptureOptionsCallback> mCallbacks =
+            new RemoteCallbackList<>();
+
     final GlobalContentCaptureOptions mGlobalContentCaptureOptions =
             new GlobalContentCaptureOptions();
 
@@ -497,16 +500,15 @@
     }
 
     void updateOptions(String packageName, ContentCaptureOptions options) {
-        ArraySet<CallbackRecord> records;
-        synchronized (mLock) {
-            records = mContentCaptureManagerServiceStub.mCallbacks.get(packageName);
-            if (records != null) {
-                int N = records.size();
-                for (int i = 0; i < N; i++) {
-                    records.valueAt(i).setContentCaptureOptions(options);
+        mCallbacks.broadcast((callback, pkg) -> {
+            if (pkg.equals(packageName)) {
+                try {
+                    callback.setContentCaptureOptions(options);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Unable to send setContentCaptureOptions(): " + e);
                 }
             }
-        }
+        });
     }
 
     private ActivityManagerInternal getAmInternal() {
@@ -616,8 +618,6 @@
     }
 
     final class ContentCaptureManagerServiceStub extends IContentCaptureManager.Stub {
-        @GuardedBy("mLock")
-        private final ArrayMap<String, ArraySet<CallbackRecord>> mCallbacks = new ArrayMap<>();
 
         @Override
         public void startSession(@NonNull IBinder activityToken,
@@ -778,39 +778,19 @@
                 IContentCaptureOptionsCallback callback) {
             assertCalledByPackageOwner(packageName);
 
-            CallbackRecord record = new CallbackRecord(callback, packageName);
-            record.registerObserver();
-
-            synchronized (mLock) {
-                ArraySet<CallbackRecord> records = mCallbacks.get(packageName);
-                if (records == null) {
-                    records = new ArraySet<>();
-                }
-                records.add(record);
-                mCallbacks.put(packageName, records);
-            }
+            mCallbacks.register(callback, packageName);
 
             // Set options here in case it was updated before this was registered.
             final int userId = UserHandle.getCallingUserId();
             final ContentCaptureOptions options = mGlobalContentCaptureOptions.getOptions(userId,
                     packageName);
             if (options != null) {
-                record.setContentCaptureOptions(options);
-            }
-        }
-
-        private void unregisterContentCaptureOptionsCallback(CallbackRecord record) {
-            synchronized (mLock) {
-                ArraySet<CallbackRecord> records = mCallbacks.get(record.mPackageName);
-                if (records != null) {
-                    records.remove(record);
-                }
-
-                if (records == null || records.isEmpty()) {
-                    mCallbacks.remove(record.mPackageName);
+                try {
+                    callback.setContentCaptureOptions(options);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Unable to send setContentCaptureOptions(): " + e);
                 }
             }
-            record.unregisterObserver();
         }
 
         @Override
@@ -1277,39 +1257,4 @@
                     mDataShareRequest.getPackageName());
         }
     }
-
-    private final class CallbackRecord implements IBinder.DeathRecipient {
-        private final String mPackageName;
-        private final IContentCaptureOptionsCallback mCallback;
-
-        private CallbackRecord(IContentCaptureOptionsCallback callback, String packageName) {
-            mCallback = callback;
-            mPackageName = packageName;
-        }
-
-        private void setContentCaptureOptions(ContentCaptureOptions options) {
-            try {
-                mCallback.setContentCaptureOptions(options);
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Unable to send setContentCaptureOptions(): " + e);
-            }
-        }
-
-        private void registerObserver() {
-            try {
-                mCallback.asBinder().linkToDeath(this, 0);
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Failed to register callback cleanup " + e);
-            }
-        }
-
-        private void unregisterObserver() {
-            mCallback.asBinder().unlinkToDeath(this, 0);
-        }
-
-        @Override
-        public void binderDied() {
-            mContentCaptureManagerServiceStub.unregisterContentCaptureOptionsCallback(this);
-        }
-    }
 }
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 0fe874c..ed2e625 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -225,7 +225,6 @@
         "java/com/android/server/TestNetworkService.java",
         "java/com/android/server/connectivity/AutodestructReference.java",
         "java/com/android/server/connectivity/ConnectivityConstants.java",
-        "java/com/android/server/connectivity/ConnectivityResources.java",
         "java/com/android/server/connectivity/DnsManager.java",
         "java/com/android/server/connectivity/KeepaliveTracker.java",
         "java/com/android/server/connectivity/LingerMonitor.java",
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index c295778..b089014 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -1141,4 +1141,12 @@
      */
     public abstract boolean isPackageFrozen(
             @NonNull String packageName, int callingUid, int userId);
+
+    /**
+     * Returns true if the given {@code packageName} has declared the
+     * {@code neverForLocation} flag in the {@code uses-permission} manifest tag
+     * where they request the given {@code permissionName}.
+     */
+    public abstract boolean isPackageUsesPermissionNeverForLocation(@NonNull String packageName,
+            @NonNull String permissionName);
 }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 3194bdc..0515eca 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -72,8 +72,8 @@
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkCapabilities.TRANSPORT_TEST;
 import static android.net.NetworkCapabilities.TRANSPORT_VPN;
-import static android.net.NetworkPolicyManager.RULE_NONE;
-import static android.net.NetworkPolicyManager.uidRulesToString;
+import static android.net.NetworkPolicyManager.BLOCKED_REASON_NONE;
+import static android.net.NetworkPolicyManager.blockedReasonsToString;
 import static android.net.NetworkRequest.Type.LISTEN_FOR_BEST;
 import static android.net.shared.NetworkMonitorUtils.isPrivateDnsValidationRequired;
 import static android.os.Process.INVALID_UID;
@@ -106,6 +106,8 @@
 import android.net.ConnectivityDiagnosticsManager.DataStallReport;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
+import android.net.ConnectivityManager.RestrictBackgroundStatus;
+import android.net.ConnectivityResources;
 import android.net.ConnectivitySettingsManager;
 import android.net.DataStallReportParcelable;
 import android.net.DnsResolverServiceManager;
@@ -115,9 +117,9 @@
 import android.net.IDnsResolver;
 import android.net.INetd;
 import android.net.INetworkActivityListener;
+import android.net.INetworkAgent;
 import android.net.INetworkMonitor;
 import android.net.INetworkMonitorCallbacks;
-import android.net.INetworkPolicyListener;
 import android.net.IOnCompleteListener;
 import android.net.IQosCallback;
 import android.net.ISocketKeepaliveCallback;
@@ -135,6 +137,7 @@
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkMonitorManager;
 import android.net.NetworkPolicyManager;
+import android.net.NetworkPolicyManager.NetworkPolicyCallback;
 import android.net.NetworkProvider;
 import android.net.NetworkRequest;
 import android.net.NetworkScore;
@@ -208,7 +211,6 @@
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 
-import com.android.connectivity.aidl.INetworkAgent;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.IndentingPrintWriter;
@@ -222,7 +224,6 @@
 import com.android.net.module.util.NetworkCapabilitiesUtils;
 import com.android.net.module.util.PermissionUtils;
 import com.android.server.connectivity.AutodestructReference;
-import com.android.server.connectivity.ConnectivityResources;
 import com.android.server.connectivity.DnsManager;
 import com.android.server.connectivity.DnsManager.PrivateDnsValidationUpdate;
 import com.android.server.connectivity.KeepaliveTracker;
@@ -237,7 +238,6 @@
 import com.android.server.connectivity.ProfileNetworkPreferences;
 import com.android.server.connectivity.ProxyTracker;
 import com.android.server.connectivity.QosCallbackTracker;
-import com.android.server.net.NetworkPolicyManagerInternal;
 
 import libcore.io.IoUtils;
 
@@ -285,7 +285,7 @@
     /**
      * Default URL to use for {@link #getCaptivePortalServerUrl()}. This should not be changed
      * by OEMs for configuration purposes, as this value is overridden by
-     * Settings.Global.CAPTIVE_PORTAL_HTTP_URL.
+     * ConnectivitySettingsManager.CAPTIVE_PORTAL_HTTP_URL.
      * R.string.config_networkCaptivePortalServerUrl should be overridden instead for this purpose
      * (preferably via runtime resource overlays).
      */
@@ -318,7 +318,7 @@
     protected int mNascentDelayMs;
 
     // How long to delay to removal of a pending intent based request.
-    // See Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS
+    // See ConnectivitySettingsManager.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS
     private final int mReleasePendingIntentDelayMs;
 
     private MockableSystemProperties mSystemProperties;
@@ -331,12 +331,10 @@
     private volatile boolean mLockdownEnabled;
 
     /**
-     * Stale copy of uid rules provided by NPMS. As long as they are accessed only in internal
-     * handler thread, they don't need a lock.
+     * Stale copy of uid blocked reasons provided by NPMS. As long as they are accessed only in
+     * internal handler thread, they don't need a lock.
      */
-    private SparseIntArray mUidRules = new SparseIntArray();
-    /** Flag indicating if background data is restricted. */
-    private boolean mRestrictBackground;
+    private SparseIntArray mUidBlockedReasons = new SparseIntArray();
 
     private final Context mContext;
     private final ConnectivityResources mResources;
@@ -352,7 +350,6 @@
     protected INetd mNetd;
     private NetworkStatsManager mStatsManager;
     private NetworkPolicyManager mPolicyManager;
-    private NetworkPolicyManagerInternal mPolicyManagerInternal;
     private final NetdCallback mNetdCallback;
 
     /**
@@ -510,16 +507,6 @@
     // Handle private DNS validation status updates.
     private static final int EVENT_PRIVATE_DNS_VALIDATION_UPDATE = 38;
 
-    /**
-     * Used to handle onUidRulesChanged event from NetworkPolicyManagerService.
-     */
-    private static final int EVENT_UID_RULES_CHANGED = 39;
-
-    /**
-     * Used to handle onRestrictBackgroundChanged event from NetworkPolicyManagerService.
-     */
-    private static final int EVENT_DATA_SAVER_CHANGED = 40;
-
      /**
       * Event for NetworkMonitor/NetworkAgentInfo to inform ConnectivityService that the network has
       * been tested.
@@ -596,6 +583,13 @@
     private static final int EVENT_SET_PROFILE_NETWORK_PREFERENCE = 50;
 
     /**
+     * Event to specify that reasons for why an uid is blocked changed.
+     * arg1 = uid
+     * arg2 = blockedReasons
+     */
+    private static final int EVENT_UID_BLOCKED_REASON_CHANGED = 51;
+
+    /**
      * Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
      * should be shown.
      */
@@ -1234,7 +1228,7 @@
                 new ConnectivityDiagnosticsHandler(mHandlerThread.getLooper());
 
         mReleasePendingIntentDelayMs = Settings.Secure.getInt(context.getContentResolver(),
-                Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, 5_000);
+                ConnectivitySettingsManager.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, 5_000);
 
         mLingerDelayMs = mSystemProperties.getInt(LINGER_DELAY_PROPERTY, DEFAULT_LINGER_DELAY_MS);
         // TODO: Consider making the timer customizable.
@@ -1242,9 +1236,6 @@
 
         mStatsManager = mContext.getSystemService(NetworkStatsManager.class);
         mPolicyManager = mContext.getSystemService(NetworkPolicyManager.class);
-        mPolicyManagerInternal = Objects.requireNonNull(
-                LocalServices.getService(NetworkPolicyManagerInternal.class),
-                "missing NetworkPolicyManagerInternal");
         mDnsResolver = Objects.requireNonNull(dnsresolver, "missing IDnsResolver");
         mProxyTracker = mDeps.makeProxyTracker(mContext, mHandler);
 
@@ -1253,10 +1244,10 @@
         mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
         mLocationPermissionChecker = new LocationPermissionChecker(mContext);
 
-        // To ensure uid rules are synchronized with Network Policy, register for
+        // To ensure uid state is synchronized with Network Policy, register for
         // NetworkPolicyManagerService events must happen prior to NetworkPolicyManagerService
         // reading existing policy from disk.
-        mPolicyManager.registerListener(mPolicyListener);
+        mPolicyManager.registerNetworkPolicyCallback(null, mPolicyCallback);
 
         final PowerManager powerManager = (PowerManager) context.getSystemService(
                 Context.POWER_SERVICE);
@@ -1306,10 +1297,10 @@
         mQosCallbackTracker = new QosCallbackTracker(mHandler, mNetworkRequestCounter);
 
         final int dailyLimit = Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT,
+                ConnectivitySettingsManager.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT,
                 LingerMonitor.DEFAULT_NOTIFICATION_DAILY_LIMIT);
         final long rateLimit = Settings.Global.getLong(mContext.getContentResolver(),
-                Settings.Global.NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS,
+                ConnectivitySettingsManager.NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS,
                 LingerMonitor.DEFAULT_NOTIFICATION_RATE_LIMIT_MILLIS);
         mLingerMonitor = new LingerMonitor(mContext, mNotifier, dailyLimit, rateLimit);
 
@@ -1344,7 +1335,7 @@
         netCap.addCapability(NET_CAPABILITY_INTERNET);
         netCap.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
         netCap.removeCapability(NET_CAPABILITY_NOT_VPN);
-        netCap.setUids(Collections.singleton(uids));
+        netCap.setUids(UidRange.toIntRanges(Collections.singleton(uids)));
         return netCap;
     }
 
@@ -1427,10 +1418,10 @@
     }
 
     private void handleConfigureAlwaysOnNetworks() {
-        handleAlwaysOnNetworkRequest(
-                mDefaultMobileDataRequest, Settings.Global.MOBILE_DATA_ALWAYS_ON, true);
-        handleAlwaysOnNetworkRequest(mDefaultWifiRequest, Settings.Global.WIFI_ALWAYS_REQUESTED,
-                false);
+        handleAlwaysOnNetworkRequest(mDefaultMobileDataRequest,
+                ConnectivitySettingsManager.MOBILE_DATA_ALWAYS_ON, true /* defaultValue */);
+        handleAlwaysOnNetworkRequest(mDefaultWifiRequest,
+                ConnectivitySettingsManager.WIFI_ALWAYS_REQUESTED, false /* defaultValue */);
         handleAlwaysOnNetworkRequest(mDefaultVehicleRequest,
                 com.android.internal.R.bool.config_vehicleInternalNetworkAlwaysRequested);
     }
@@ -1443,12 +1434,12 @@
 
         // Watch for whether or not to keep mobile data always on.
         mSettingsObserver.observe(
-                Settings.Global.getUriFor(Settings.Global.MOBILE_DATA_ALWAYS_ON),
+                Settings.Global.getUriFor(ConnectivitySettingsManager.MOBILE_DATA_ALWAYS_ON),
                 EVENT_CONFIGURE_ALWAYS_ON_NETWORKS);
 
         // Watch for whether or not to keep wifi always on.
         mSettingsObserver.observe(
-                Settings.Global.getUriFor(Settings.Global.WIFI_ALWAYS_REQUESTED),
+                Settings.Global.getUriFor(ConnectivitySettingsManager.WIFI_ALWAYS_REQUESTED),
                 EVENT_CONFIGURE_ALWAYS_ON_NETWORKS);
     }
 
@@ -1785,7 +1776,7 @@
         }
 
         // No need to check mLockdownEnabled. If it's true, getVpnUnderlyingNetworks returns null.
-        final Network[] networks = getVpnUnderlyingNetworks(Binder.getCallingUid());
+        final Network[] networks = getVpnUnderlyingNetworks(mDeps.getCallingUid());
         if (null != networks) {
             for (final Network network : networks) {
                 final NetworkCapabilities nc = getNetworkCapabilitiesInternal(network);
@@ -2002,6 +1993,18 @@
         }
     }
 
+    @Override
+    public @RestrictBackgroundStatus int getRestrictBackgroundStatusByCaller() {
+        enforceAccessPermission();
+        final int callerUid = Binder.getCallingUid();
+        final long token = Binder.clearCallingIdentity();
+        try {
+            return mPolicyManager.getRestrictBackgroundStatus(callerUid);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
     // TODO: Consider delete this function or turn it into a no-op method.
     @Override
     public NetworkState[] getAllNetworkState() {
@@ -2237,53 +2240,17 @@
         }
     }
 
-    private final INetworkPolicyListener mPolicyListener = new NetworkPolicyManager.Listener() {
+    private final NetworkPolicyCallback mPolicyCallback = new NetworkPolicyCallback() {
         @Override
-        public void onUidRulesChanged(int uid, int uidRules) {
-            mHandler.sendMessage(mHandler.obtainMessage(EVENT_UID_RULES_CHANGED, uid, uidRules));
-        }
-        @Override
-        public void onRestrictBackgroundChanged(boolean restrictBackground) {
-            // caller is NPMS, since we only register with them
-            if (LOGD_BLOCKED_NETWORKINFO) {
-                log("onRestrictBackgroundChanged(restrictBackground=" + restrictBackground + ")");
-            }
-            mHandler.sendMessage(mHandler.obtainMessage(
-                    EVENT_DATA_SAVER_CHANGED, restrictBackground ? 1 : 0, 0));
+        public void onUidBlockedReasonChanged(int uid, int blockedReasons) {
+            mHandler.sendMessage(mHandler.obtainMessage(EVENT_UID_BLOCKED_REASON_CHANGED,
+                    uid, blockedReasons));
         }
     };
 
-    void handleUidRulesChanged(int uid, int newRules) {
-        // skip update when we've already applied rules
-        final int oldRules = mUidRules.get(uid, RULE_NONE);
-        if (oldRules == newRules) return;
-
-        maybeNotifyNetworkBlockedForNewUidRules(uid, newRules);
-
-        if (newRules == RULE_NONE) {
-            mUidRules.delete(uid);
-        } else {
-            mUidRules.put(uid, newRules);
-        }
-    }
-
-    void handleRestrictBackgroundChanged(boolean restrictBackground) {
-        if (mRestrictBackground == restrictBackground) return;
-
-        final List<UidRange> blockedRanges = mVpnBlockedUidRanges;
-        for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
-            final boolean curMetered = nai.networkCapabilities.isMetered();
-            maybeNotifyNetworkBlocked(nai, curMetered, curMetered, mRestrictBackground,
-                    restrictBackground, blockedRanges, blockedRanges);
-        }
-
-        mRestrictBackground = restrictBackground;
-    }
-
-    private boolean isUidBlockedByRules(int uid, int uidRules, boolean isNetworkMetered,
-            boolean isBackgroundRestricted) {
-        return mPolicyManager.checkUidNetworkingBlocked(uid, uidRules, isNetworkMetered,
-                isBackgroundRestricted);
+    void handleUidBlockedReasonChanged(int uid, int blockedReasons) {
+        maybeNotifyNetworkBlockedForNewState(uid, blockedReasons);
+        mUidBlockedReasons.put(uid, blockedReasons);
     }
 
     private boolean checkAnyPermissionOf(String... permissions) {
@@ -2757,19 +2724,16 @@
         pw.decreaseIndent();
         pw.println();
 
-        pw.print("Restrict background: ");
-        pw.println(mRestrictBackground);
-        pw.println();
-
         pw.println("Status for known UIDs:");
         pw.increaseIndent();
-        final int size = mUidRules.size();
+        final int size = mUidBlockedReasons.size();
         for (int i = 0; i < size; i++) {
             // Don't crash if the array is modified while dumping in bugreports.
             try {
-                final int uid = mUidRules.keyAt(i);
-                final int uidRules = mUidRules.get(uid, RULE_NONE);
-                pw.println("UID=" + uid + " rules=" + uidRulesToString(uidRules));
+                final int uid = mUidBlockedReasons.keyAt(i);
+                final int blockedReasons = mUidBlockedReasons.valueAt(i);
+                pw.println("UID=" + uid + " blockedReasons="
+                        + blockedReasonsToString(blockedReasons));
             } catch (ArrayIndexOutOfBoundsException e) {
                 pw.println("  ArrayIndexOutOfBoundsException");
             } catch (ConcurrentModificationException e) {
@@ -2904,7 +2868,7 @@
             if (0 == defaultRequest.mRequests.size()) {
                 pw.println("none, this should never occur.");
             } else {
-                pw.println(defaultRequest.mRequests.get(0).networkCapabilities.getUids());
+                pw.println(defaultRequest.mRequests.get(0).networkCapabilities.getUidRanges());
             }
             pw.decreaseIndent();
             pw.decreaseIndent();
@@ -3005,6 +2969,9 @@
                 case NetworkAgent.EVENT_SET_EXPLICITLY_SELECTED: {
                     if (nai.everConnected) {
                         loge("ERROR: cannot call explicitlySelected on already-connected network");
+                        // Note that if the NAI had been connected, this would affect the
+                        // score, and therefore would require re-mixing the score and performing
+                        // a rematch.
                     }
                     nai.networkAgentConfig.explicitlySelected = toBool(msg.arg1);
                     nai.networkAgentConfig.acceptUnvalidated = toBool(msg.arg1) && toBool(msg.arg2);
@@ -3110,7 +3077,8 @@
                         nai.lastCaptivePortalDetected = visible;
                         nai.everCaptivePortalDetected |= visible;
                         if (nai.lastCaptivePortalDetected &&
-                            Settings.Global.CAPTIVE_PORTAL_MODE_AVOID == getCaptivePortalMode()) {
+                                ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_AVOID
+                                        == getCaptivePortalMode()) {
                             if (DBG) log("Avoiding captive portal network: " + nai.toShortString());
                             nai.onPreventAutomaticReconnect();
                             teardownUnneededNetwork(nai);
@@ -3221,8 +3189,8 @@
 
         private int getCaptivePortalMode() {
             return Settings.Global.getInt(mContext.getContentResolver(),
-                    Settings.Global.CAPTIVE_PORTAL_MODE,
-                    Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
+                    ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE,
+                    ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_PROMPT);
         }
 
         private boolean maybeHandleNetworkAgentInfoMessage(Message msg) {
@@ -3690,7 +3658,7 @@
                 log("Replacing " + existingRequest.mRequests.get(0) + " with "
                         + nri.mRequests.get(0) + " because their intents matched.");
             }
-            handleReleaseNetworkRequest(existingRequest.mRequests.get(0), getCallingUid(),
+            handleReleaseNetworkRequest(existingRequest.mRequests.get(0), mDeps.getCallingUid(),
                     /* callOnUnavailable */ false);
         }
         handleRegisterNetworkRequest(nri);
@@ -4088,6 +4056,7 @@
             // network, we should respect the user's option and don't need to popup the
             // PARTIAL_CONNECTIVITY notification to user again.
             nai.networkAgentConfig.acceptPartialConnectivity = accept;
+            nai.updateScoreForNetworkAgentConfigUpdate();
             rematchAllNetworksAndRequests();
             sendUpdatedScoreToFactories(nai);
         }
@@ -4350,7 +4319,7 @@
 
         Intent intent = new Intent(action);
         if (type != NotificationType.PRIVATE_DNS_BROKEN) {
-            intent.setData(Uri.fromParts("netId", Integer.toString(nai.network.getNetId()), null));
+            intent.putExtra(ConnectivityManager.EXTRA_NETWORK, nai.network);
             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             // Some OEMs have their own Settings package. Thus, need to get the current using
             // Settings package name instead of just use default name "com.android.settings".
@@ -4446,7 +4415,13 @@
         final NetworkPolicyManager netPolicyManager =
                  mContext.getSystemService(NetworkPolicyManager.class);
 
-        final int networkPreference = netPolicyManager.getMultipathPreference(network);
+        final long token = Binder.clearCallingIdentity();
+        final int networkPreference;
+        try {
+            networkPreference = netPolicyManager.getMultipathPreference(network);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
         if (networkPreference != 0) {
             return networkPreference;
         }
@@ -4565,11 +4540,8 @@
                     handlePrivateDnsValidationUpdate(
                             (PrivateDnsValidationUpdate) msg.obj);
                     break;
-                case EVENT_UID_RULES_CHANGED:
-                    handleUidRulesChanged(msg.arg1, msg.arg2);
-                    break;
-                case EVENT_DATA_SAVER_CHANGED:
-                    handleRestrictBackgroundChanged(toBool(msg.arg1));
+                case EVENT_UID_BLOCKED_REASON_CHANGED:
+                    handleUidBlockedReasonChanged(msg.arg1, msg.arg2);
                     break;
                 case EVENT_SET_REQUIRE_VPN_FOR_UIDS:
                     handleSetRequireVpnForUids(toBool(msg.arg1), (UidRange[]) msg.obj);
@@ -5042,8 +5014,8 @@
 
         for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
             final boolean curMetered = nai.networkCapabilities.isMetered();
-            maybeNotifyNetworkBlocked(nai, curMetered, curMetered, mRestrictBackground,
-                    mRestrictBackground, mVpnBlockedUidRanges, newVpnBlockedUidRanges);
+            maybeNotifyNetworkBlocked(nai, curMetered, curMetered,
+                    mVpnBlockedUidRanges, newVpnBlockedUidRanges);
         }
 
         mVpnBlockedUidRanges = newVpnBlockedUidRanges;
@@ -5321,9 +5293,8 @@
         private Set<UidRange> getUids() {
             // networkCapabilities.getUids() returns a defensive copy.
             // multilayer requests will all have the same uids so return the first one.
-            final Set<UidRange> uids = null == mRequests.get(0).networkCapabilities.getUids()
-                    ? new ArraySet<>() : mRequests.get(0).networkCapabilities.getUids();
-            return uids;
+            final Set<UidRange> uids = mRequests.get(0).networkCapabilities.getUidRanges();
+            return (null == uids) ? new ArraySet<>() : uids;
         }
 
         NetworkRequestInfo(@NonNull final NetworkRequest r, @Nullable final PendingIntent pi,
@@ -5776,14 +5747,14 @@
     private void releasePendingNetworkRequestWithDelay(PendingIntent operation) {
         mHandler.sendMessageDelayed(
                 mHandler.obtainMessage(EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT,
-                getCallingUid(), 0, operation), mReleasePendingIntentDelayMs);
+                mDeps.getCallingUid(), 0, operation), mReleasePendingIntentDelayMs);
     }
 
     @Override
     public void releasePendingNetworkRequest(PendingIntent operation) {
         Objects.requireNonNull(operation, "PendingIntent cannot be null.");
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT,
-                getCallingUid(), 0, operation));
+                mDeps.getCallingUid(), 0, operation));
     }
 
     // In order to implement the compatibility measure for pre-M apps that call
@@ -5880,7 +5851,7 @@
     public void releaseNetworkRequest(NetworkRequest networkRequest) {
         ensureNetworkRequestHasType(networkRequest);
         mHandler.sendMessage(mHandler.obtainMessage(
-                EVENT_RELEASE_NETWORK_REQUEST, getCallingUid(), 0, networkRequest));
+                EVENT_RELEASE_NETWORK_REQUEST, mDeps.getCallingUid(), 0, networkRequest));
     }
 
     private void handleRegisterNetworkProvider(NetworkProviderInfo npi) {
@@ -6129,7 +6100,7 @@
         for (final NetworkRequestInfo nri : mDefaultNetworkRequests) {
             // Currently, all network requests will have the same uids therefore checking the first
             // one is sufficient. If/when uids are tracked at the nri level, this can change.
-            final Set<UidRange> uids = nri.mRequests.get(0).networkCapabilities.getUids();
+            final Set<UidRange> uids = nri.mRequests.get(0).networkCapabilities.getUidRanges();
             if (null == uids) {
                 continue;
             }
@@ -6570,7 +6541,7 @@
             return;
         }
 
-        final Set<UidRange> ranges = nai.networkCapabilities.getUids();
+        final Set<UidRange> ranges = nai.networkCapabilities.getUidRanges();
         final int vpnAppUid = nai.networkCapabilities.getOwnerUid();
         // TODO: this create a window of opportunity for apps to receive traffic between the time
         // when the old rules are removed and the time when new rules are added. To fix this,
@@ -6826,8 +6797,8 @@
         final boolean meteredChanged = oldMetered != newMetered;
 
         if (meteredChanged) {
-            maybeNotifyNetworkBlocked(nai, oldMetered, newMetered, mRestrictBackground,
-                    mRestrictBackground, mVpnBlockedUidRanges, mVpnBlockedUidRanges);
+            maybeNotifyNetworkBlocked(nai, oldMetered, newMetered,
+                    mVpnBlockedUidRanges, mVpnBlockedUidRanges);
         }
 
         final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING)
@@ -6935,8 +6906,8 @@
 
     private void updateUids(NetworkAgentInfo nai, NetworkCapabilities prevNc,
             NetworkCapabilities newNc) {
-        Set<UidRange> prevRanges = null == prevNc ? null : prevNc.getUids();
-        Set<UidRange> newRanges = null == newNc ? null : newNc.getUids();
+        Set<UidRange> prevRanges = null == prevNc ? null : prevNc.getUidRanges();
+        Set<UidRange> newRanges = null == newNc ? null : newNc.getUidRanges();
         if (null == prevRanges) prevRanges = new ArraySet<>();
         if (null == newRanges) newRanges = new ArraySet<>();
         final Set<UidRange> prevRangesCopy = new ArraySet<>(prevRanges);
@@ -7950,8 +7921,8 @@
         final boolean metered = nai.networkCapabilities.isMetered();
         boolean blocked;
         blocked = isUidBlockedByVpn(nri.mUid, mVpnBlockedUidRanges);
-        blocked |= isUidBlockedByRules(nri.mUid, mUidRules.get(nri.mUid),
-                metered, mRestrictBackground);
+        blocked |= NetworkPolicyManager.isUidBlocked(
+                mUidBlockedReasons.get(nri.mUid, BLOCKED_REASON_NONE), metered);
         callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE, blocked ? 1 : 0);
     }
 
@@ -7969,16 +7940,14 @@
      *
      * @param nai The target NetworkAgentInfo.
      * @param oldMetered True if the previous network capabilities is metered.
-     * @param newRestrictBackground True if data saver is enabled.
      */
     private void maybeNotifyNetworkBlocked(NetworkAgentInfo nai, boolean oldMetered,
-            boolean newMetered, boolean oldRestrictBackground, boolean newRestrictBackground,
-            List<UidRange> oldBlockedUidRanges, List<UidRange> newBlockedUidRanges) {
+            boolean newMetered, List<UidRange> oldBlockedUidRanges,
+            List<UidRange> newBlockedUidRanges) {
 
         for (int i = 0; i < nai.numNetworkRequests(); i++) {
             NetworkRequest nr = nai.requestAt(i);
             NetworkRequestInfo nri = mNetworkRequests.get(nr);
-            final int uidRules = mUidRules.get(nri.mUid);
             final boolean oldBlocked, newBlocked, oldVpnBlocked, newVpnBlocked;
 
             oldVpnBlocked = isUidBlockedByVpn(nri.mUid, oldBlockedUidRanges);
@@ -7986,10 +7955,11 @@
                     ? isUidBlockedByVpn(nri.mUid, newBlockedUidRanges)
                     : oldVpnBlocked;
 
-            oldBlocked = oldVpnBlocked || isUidBlockedByRules(nri.mUid, uidRules, oldMetered,
-                    oldRestrictBackground);
-            newBlocked = newVpnBlocked || isUidBlockedByRules(nri.mUid, uidRules, newMetered,
-                    newRestrictBackground);
+            final int blockedReasons = mUidBlockedReasons.get(nri.mUid, BLOCKED_REASON_NONE);
+            oldBlocked = oldVpnBlocked || NetworkPolicyManager.isUidBlocked(
+                    blockedReasons, oldMetered);
+            newBlocked = newVpnBlocked || NetworkPolicyManager.isUidBlocked(
+                    blockedReasons, newMetered);
 
             if (oldBlocked != newBlocked) {
                 callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED,
@@ -7999,19 +7969,20 @@
     }
 
     /**
-     * Notify apps with a given UID of the new blocked state according to new uid rules.
+     * Notify apps with a given UID of the new blocked state according to new uid state.
      * @param uid The uid for which the rules changed.
-     * @param newRules The new rules to apply.
+     * @param blockedReasons The reasons for why an uid is blocked.
      */
-    private void maybeNotifyNetworkBlockedForNewUidRules(int uid, int newRules) {
+    private void maybeNotifyNetworkBlockedForNewState(int uid, int blockedReasons) {
         for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
             final boolean metered = nai.networkCapabilities.isMetered();
             final boolean vpnBlocked = isUidBlockedByVpn(uid, mVpnBlockedUidRanges);
             final boolean oldBlocked, newBlocked;
-            oldBlocked = vpnBlocked || isUidBlockedByRules(
-                    uid, mUidRules.get(uid), metered, mRestrictBackground);
-            newBlocked = vpnBlocked || isUidBlockedByRules(
-                    uid, newRules, metered, mRestrictBackground);
+
+            oldBlocked = vpnBlocked || NetworkPolicyManager.isUidBlocked(
+                    mUidBlockedReasons.get(uid, BLOCKED_REASON_NONE), metered);
+            newBlocked = vpnBlocked || NetworkPolicyManager.isUidBlocked(
+                    blockedReasons, metered);
             if (oldBlocked == newBlocked) {
                 continue;
             }
@@ -8159,7 +8130,7 @@
         }
 
         settingUrl = Settings.Global.getString(mContext.getContentResolver(),
-                Settings.Global.CAPTIVE_PORTAL_HTTP_URL);
+                ConnectivitySettingsManager.CAPTIVE_PORTAL_HTTP_URL);
         if (!TextUtils.isEmpty(settingUrl)) {
             return settingUrl;
         }
@@ -8241,7 +8212,7 @@
         // restore private DNS settings to default mode (opportunistic)
         if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_PRIVATE_DNS)) {
             Settings.Global.putString(mContext.getContentResolver(),
-                    Settings.Global.PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_OPPORTUNISTIC);
+                    ConnectivitySettingsManager.PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_OPPORTUNISTIC);
         }
 
         Settings.Global.putString(mContext.getContentResolver(),
@@ -8358,7 +8329,7 @@
 
         final NetworkAgentInfo vpn = getVpnForUid(uid);
         if (vpn == null || getVpnType(vpn) != VpnManager.TYPE_VPN_SERVICE
-                || vpn.networkCapabilities.getOwnerUid() != Binder.getCallingUid()) {
+                || vpn.networkCapabilities.getOwnerUid() != mDeps.getCallingUid()) {
             return INVALID_UID;
         }
 
@@ -8997,13 +8968,13 @@
             if (networkAgent.networkCapabilities.hasTransport(
                     NetworkCapabilities.TRANSPORT_CELLULAR)) {
                 timeout = Settings.Global.getInt(mContext.getContentResolver(),
-                        Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE,
+                        ConnectivitySettingsManager.DATA_ACTIVITY_TIMEOUT_MOBILE,
                         10);
                 type = NetworkCapabilities.TRANSPORT_CELLULAR;
             } else if (networkAgent.networkCapabilities.hasTransport(
                     NetworkCapabilities.TRANSPORT_WIFI)) {
                 timeout = Settings.Global.getInt(mContext.getContentResolver(),
-                        Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI,
+                        ConnectivitySettingsManager.DATA_ACTIVITY_TIMEOUT_WIFI,
                         15);
                 type = NetworkCapabilities.TRANSPORT_WIFI;
             } else {
@@ -9267,7 +9238,7 @@
             final ArrayList<NetworkRequest> nrs = new ArrayList<>();
             nrs.add(createNetworkRequest(NetworkRequest.Type.REQUEST, pref.capabilities));
             nrs.add(createDefaultRequest());
-            setNetworkRequestUids(nrs, pref.capabilities.getUids());
+            setNetworkRequestUids(nrs, UidRange.fromIntRanges(pref.capabilities.getUids()));
             final NetworkRequestInfo nri = new NetworkRequestInfo(nrs);
             result.add(nri);
         }
@@ -9483,9 +9454,8 @@
 
     private static void setNetworkRequestUids(@NonNull final List<NetworkRequest> requests,
             @NonNull final Set<UidRange> uids) {
-        final Set<UidRange> ranges = new ArraySet<>(uids);
         for (final NetworkRequest req : requests) {
-            req.networkCapabilities.setUids(ranges);
+            req.networkCapabilities.setUids(UidRange.toIntRanges(uids));
         }
     }
 
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index bab6deb..af791cb 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -162,7 +162,7 @@
         GESTURE_CAMERA_DOUBLE_TAP_POWER(660),
 
         @UiEvent(doc = "The user multi-tapped power quickly enough to signal an emergency.")
-        GESTURE_PANIC_TAP_POWER(661);
+        GESTURE_EMERGENCY_TAP_POWER(661);
 
         private final int mId;
 
@@ -508,7 +508,7 @@
         } else if (launchEmergencyGesture) {
             Slog.i(TAG, "Emergency gesture detected, launching.");
             launchEmergencyGesture = handleEmergencyGesture();
-            mUiEventLogger.log(GestureLauncherEvent.GESTURE_PANIC_TAP_POWER);
+            mUiEventLogger.log(GestureLauncherEvent.GESTURE_EMERGENCY_TAP_POWER);
         }
         mMetricsLogger.histogram("power_consecutive_short_tap_count",
                 mPowerButtonSlowConsecutiveTaps);
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 4c3c6ef..794cb93 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -1651,7 +1651,7 @@
                         c.getMode(),
                         c.getSourceAddress(),
                         c.getDestinationAddress(),
-                        (c.getNetwork() != null) ? c.getNetwork().netId : 0,
+                        (c.getNetwork() != null) ? c.getNetwork().getNetId() : 0,
                         spiRecord.getSpi(),
                         c.getMarkValue(),
                         c.getMarkMask(),
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 10d6570..3ea0ce1 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -643,7 +643,7 @@
                 String route, String gateway, String ifName) throws RemoteException {
             final RouteInfo processRoute = new RouteInfo(new IpPrefix(route),
                     ("".equals(gateway)) ? null : InetAddresses.parseNumericAddress(gateway),
-                    ifName);
+                    ifName, RouteInfo.RTN_UNICAST);
             mDaemonHandler.post(() -> notifyRouteChange(updated, processRoute));
         }
 
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index 871de0d..ebd32e8 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -521,13 +521,6 @@
         return pinKeys;
     }
 
-    private static boolean shouldPinSplitApks() {
-        // For now this is disabled by default bcause the pinlist support for split APKs are
-        // missing in the toolchain. This flag should be removed once it is ready. b/174697187.
-        return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT,
-                "pin_split_apks", false);
-    }
-
     private synchronized ArraySet<Integer> getPinKeys() {
         return mPinKeys;
     }
@@ -685,7 +678,7 @@
         List<String> apks = new ArrayList<>();
         apks.add(appInfo.sourceDir);
 
-        if (shouldPinSplitApks() && appInfo.splitSourceDirs != null) {
+        if (appInfo.splitSourceDirs != null) {
             for (String splitApk : appInfo.splitSourceDirs) {
                 apks.add(splitApk);
             }
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 8b5bb1d..7f96aff 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -18,6 +18,7 @@
 
 import static android.Manifest.permission.ACCESS_MTP;
 import static android.Manifest.permission.INSTALL_PACKAGES;
+import static android.Manifest.permission.MANAGE_EXTERNAL_STORAGE;
 import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
 import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.AppOpsManager.OP_LEGACY_STORAGE;
@@ -1791,7 +1792,7 @@
     public StorageManagerService(Context context) {
         sSelf = this;
         mVoldAppDataIsolationEnabled = SystemProperties.getBoolean(
-                ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, true);
+                ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false);
         mContext = context;
         mResolver = mContext.getContentResolver();
         mCallbacks = new Callbacks(FgThread.get().getLooper());
@@ -4606,6 +4607,25 @@
         }
 
         @Override
+        public boolean hasExternalStorageAccess(int uid, String packageName) {
+            try {
+                if (mIPackageManager.checkUidPermission(
+                                MANAGE_EXTERNAL_STORAGE, uid) == PERMISSION_GRANTED) {
+                    return true;
+                }
+
+                if (mIAppOpsService.checkOperation(
+                                OP_MANAGE_EXTERNAL_STORAGE, uid, packageName) == MODE_ALLOWED) {
+                    return true;
+                }
+            } catch (RemoteException e) {
+                Slog.w("Failed to check MANAGE_EXTERNAL_STORAGE access for " + packageName, e);
+            }
+
+            return false;
+        }
+
+        @Override
         public void addResetListener(StorageManagerInternal.ResetListener listener) {
             synchronized (mResetListeners) {
                 mResetListeners.add(listener);
diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java
index 56aabc20..d756c1f 100644
--- a/services/core/java/com/android/server/VpnManagerService.java
+++ b/services/core/java/com/android/server/VpnManagerService.java
@@ -352,7 +352,10 @@
     @Override
     public void startLegacyVpn(VpnProfile profile) {
         int user = UserHandle.getUserId(mDeps.getCallingUid());
-        final LinkProperties egress = mCm.getActiveLinkProperties();
+        // Note that if the caller is not system (uid >= Process.FIRST_APPLICATION_UID),
+        // the code might not work well since getActiveNetwork might return null if the uid is
+        // blocked by NetworkPolicyManagerService.
+        final LinkProperties egress = mCm.getLinkProperties(mCm.getActiveNetwork());
         if (egress == null) {
             throw new IllegalStateException("Missing active network connection");
         }
diff --git a/services/core/java/com/android/server/WatchableIntentResolver.java b/services/core/java/com/android/server/WatchedIntentResolver.java
similarity index 97%
rename from services/core/java/com/android/server/WatchableIntentResolver.java
rename to services/core/java/com/android/server/WatchedIntentResolver.java
index 2ef94f1..e514f3c 100644
--- a/services/core/java/com/android/server/WatchableIntentResolver.java
+++ b/services/core/java/com/android/server/WatchedIntentResolver.java
@@ -31,7 +31,7 @@
  * @param <R> The resolver type.
  * {@hide}
  */
-public abstract class WatchableIntentResolver<F, R extends Object>
+public abstract class WatchedIntentResolver<F, R extends Object>
         extends IntentResolver<F, R>
         implements Watchable {
 
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 3c445ae..1b352c7 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -160,6 +160,7 @@
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 import java.util.function.Predicate;
 
@@ -559,6 +560,45 @@
         return smap != null ? smap.mStartingBackground.size() >= mMaxStartingBackground : false;
     }
 
+    boolean hasForegroundServiceNotificationLocked(String pkg, int userId, String channelId) {
+        final ServiceMap smap = mServiceMap.get(userId);
+        if (smap != null) {
+            for (int i = 0; i < smap.mServicesByInstanceName.size(); i++) {
+                final ServiceRecord sr = smap.mServicesByInstanceName.valueAt(i);
+                if (sr.appInfo.packageName.equals(pkg) && sr.isForeground) {
+                    if (Objects.equals(sr.foregroundNoti.getChannelId(), channelId)) {
+                        if (DEBUG_FOREGROUND_SERVICE) {
+                            Slog.d(TAG_SERVICE, "Channel u" + userId + "/pkg=" + pkg
+                                    + "/channelId=" + channelId
+                                    + " has fg service notification");
+                        }
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    void stopForegroundServicesForChannelLocked(String pkg, int userId, String channelId) {
+        final ServiceMap smap = mServiceMap.get(userId);
+        if (smap != null) {
+            for (int i = 0; i < smap.mServicesByInstanceName.size(); i++) {
+                final ServiceRecord sr = smap.mServicesByInstanceName.valueAt(i);
+                if (sr.appInfo.packageName.equals(pkg) && sr.isForeground) {
+                    if (Objects.equals(sr.foregroundNoti.getChannelId(), channelId)) {
+                        if (DEBUG_FOREGROUND_SERVICE) {
+                            Slog.d(TAG_SERVICE, "Stopping FGS u" + userId + "/pkg=" + pkg
+                                    + "/channelId=" + channelId
+                                    + " for conversation channel clear");
+                        }
+                        stopServiceLocked(sr, false);
+                    }
+                }
+            }
+        }
+    }
+
     private ServiceMap getServiceMapLocked(int callingUser) {
         ServiceMap smap = mServiceMap.get(callingUser);
         if (smap == null) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 83cbf66..c4548a3 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -15911,6 +15911,22 @@
         }
 
         @Override
+        public boolean hasForegroundServiceNotification(String pkg, int userId,
+                String channelId) {
+            synchronized (ActivityManagerService.this) {
+                return mServices.hasForegroundServiceNotificationLocked(pkg, userId, channelId);
+            }
+        }
+
+        @Override
+        public void stopForegroundServicesForChannel(String pkg, int userId,
+                String channelId) {
+            synchronized (ActivityManagerService.this) {
+                mServices.stopForegroundServicesForChannelLocked(pkg, userId, channelId);
+            }
+        }
+
+        @Override
         public void registerProcessObserver(IProcessObserver processObserver) {
             ActivityManagerService.this.registerProcessObserver(processObserver);
         }
@@ -16147,7 +16163,12 @@
         }
     }
 
-    public void waitForBroadcastIdle(PrintWriter pw) {
+    @Override
+    public void waitForBroadcastIdle() {
+        waitForBroadcastIdle(/* printWriter= */ null);
+    }
+
+    public void waitForBroadcastIdle(@Nullable PrintWriter pw) {
         enforceCallingPermission(permission.DUMP, "waitForBroadcastIdle()");
         while (true) {
             boolean idle = true;
@@ -16155,9 +16176,11 @@
                 for (BroadcastQueue queue : mBroadcastQueues) {
                     if (!queue.isIdle()) {
                         final String msg = "Waiting for queue " + queue + " to become idle...";
-                        pw.println(msg);
-                        pw.println(queue.describeState());
-                        pw.flush();
+                        if (pw != null) {
+                            pw.println(msg);
+                            pw.println(queue.describeState());
+                            pw.flush();
+                        }
                         Slog.v(TAG, msg);
                         queue.cancelDeferrals();
                         idle = false;
@@ -16167,8 +16190,10 @@
 
             if (idle) {
                 final String msg = "All broadcast queues are idle!";
-                pw.println(msg);
-                pw.flush();
+                if (pw != null) {
+                    pw.println(msg);
+                    pw.flush();
+                }
                 Slog.v(TAG, msg);
                 return;
             } else {
diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS
index 9e79b02..273b9c3 100644
--- a/services/core/java/com/android/server/am/OWNERS
+++ b/services/core/java/com/android/server/am/OWNERS
@@ -30,6 +30,10 @@
 michaelwr@google.com
 narayan@google.com
 
+# Voice Interaction
+per-file *Assist* = file:/core/java/android/service/voice/OWNERS
+per-file *Voice* = file:/core/java/android/service/voice/OWNERS
+
 per-file SettingsToPropertiesMapper.java = omakoto@google.com, svetoslavganov@google.com, yamasani@google.com
 
 per-file CarUserSwitchingDialog.java = keunyoung@google.com, felipeal@google.com, gurunagarajan@google.com
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 4972aa7..51bcde8 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -786,7 +786,7 @@
         mAppDataIsolationEnabled =
                 SystemProperties.getBoolean(ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY, true);
         mVoldAppDataIsolationEnabled = SystemProperties.getBoolean(
-                ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, true);
+                ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false);
         mAppDataIsolationAllowlistedApps = new ArrayList<>(
                 SystemConfig.getInstance().getAppDataIsolationWhitelistedApps());
 
@@ -1598,7 +1598,8 @@
         }
     }
 
-    private int[] computeGidsForProcess(int mountExternal, int uid, int[] permGids) {
+    private int[] computeGidsForProcess(int mountExternal, int uid, int[] permGids,
+            boolean externalStorageAccess) {
         ArrayList<Integer> gidList = new ArrayList<>(permGids.length + 5);
 
         final int sharedAppGid = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
@@ -1644,6 +1645,11 @@
             // PublicVolumes: /mnt/media_rw/<volume>
             gidList.add(Process.MEDIA_RW_GID);
         }
+        if (externalStorageAccess) {
+            // Apps with MANAGE_EXTERNAL_STORAGE PERMISSION need the external_storage gid to access
+            // USB OTG (unreliable) volumes on /mnt/media_rw/<vol name>
+            gidList.add(Process.EXTERNAL_STORAGE_GID);
+        }
 
         int[] gidArray = new int[gidList.size()];
         for (int i = 0; i < gidArray.length; i++) {
@@ -1805,6 +1811,7 @@
             int uid = app.uid;
             int[] gids = null;
             int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
+            boolean externalStorageAccess = false;
             if (!app.isolated) {
                 int[] permGids = null;
                 try {
@@ -1816,6 +1823,8 @@
                             StorageManagerInternal.class);
                     mountExternal = storageManagerInternal.getExternalStorageMountMode(uid,
                             app.info.packageName);
+                    externalStorageAccess = storageManagerInternal.hasExternalStorageAccess(uid,
+                            app.info.packageName);
                 } catch (RemoteException e) {
                     throw e.rethrowAsRuntimeException();
                 }
@@ -1835,7 +1844,7 @@
                     }
                 }
 
-                gids = computeGidsForProcess(mountExternal, uid, permGids);
+                gids = computeGidsForProcess(mountExternal, uid, permGids, externalStorageAccess);
             }
             app.setMountMode(mountExternal);
             checkSlow(startTime, "startProcess: building args");
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
index 2c0a589..ad5a65c 100644
--- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
@@ -173,7 +173,9 @@
         if (!checkHibernationEnabled("isHibernatingForUser")) {
             return false;
         }
-
+        getContext().enforceCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_APP_HIBERNATION,
+                "Caller does not have MANAGE_APP_HIBERNATION permission.");
         userId = handleIncomingUser(userId, "isHibernating");
         if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
             Slog.e(TAG, "Attempt to get hibernation state of stopped or nonexistent user "
@@ -202,6 +204,9 @@
         if (!checkHibernationEnabled("isHibernatingGlobally")) {
             return false;
         }
+        getContext().enforceCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_APP_HIBERNATION,
+                "Caller does not have MANAGE_APP_HIBERNATION permission.");
         synchronized (mLock) {
             GlobalLevelState state = mGlobalHibernationStates.get(packageName);
             if (state == null) {
@@ -223,6 +228,9 @@
         if (!checkHibernationEnabled("setHibernatingForUser")) {
             return;
         }
+        getContext().enforceCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_APP_HIBERNATION,
+                "Caller does not have MANAGE_APP_HIBERNATION permission.");
         userId = handleIncomingUser(userId, "setHibernating");
         if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
             Slog.w(TAG, "Attempt to set hibernation state for a stopped or nonexistent user "
@@ -263,6 +271,9 @@
         if (!checkHibernationEnabled("setHibernatingGlobally")) {
             return;
         }
+        getContext().enforceCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_APP_HIBERNATION,
+                "Caller does not have MANAGE_APP_HIBERNATION permission.");
         synchronized (mLock) {
             GlobalLevelState state = mGlobalHibernationStates.get(packageName);
             if (state == null) {
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index e4fc895..88dca0c 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -395,6 +395,9 @@
                                 AudioSystem.STREAM_VOICE_CALL);
                 List<AudioDeviceAttributes> devices = AudioSystem.getDevicesForAttributes(attr);
                 if (devices.isEmpty()) {
+                    if (mAudioService.isPlatformVoice()) {
+                        Log.w(TAG, "getCommunicationDevice(): no device for phone strategy");
+                    }
                     return null;
                 }
                 device = devices.get(0);
@@ -746,7 +749,7 @@
     @GuardedBy("mDeviceStateLock")
     private void dispatchCommunicationDevice() {
         AudioDeviceInfo device = getCommunicationDevice();
-        int portId = (getCommunicationDevice() == null) ? 0 : device.getId();
+        int portId = (device == null) ? 0 : device.getId();
         if (portId == mCurCommunicationPortId) {
             return;
         }
@@ -1022,9 +1025,9 @@
         pw.println("\n" + prefix + "mPreferredCommunicationDevice: "
                 +  mPreferredCommunicationDevice);
 
+        AudioDeviceInfo device = getCommunicationDevice();
         pw.println(prefix + "Selected Communication Device: "
-                +  ((getCommunicationDevice() == null) ? "None"
-                        : new AudioDeviceAttributes(getCommunicationDevice())));
+                +  ((device == null) ? "None" : new AudioDeviceAttributes(device)));
 
         pw.println(prefix + "mCommunicationStrategyId: "
                 +  mCommunicationStrategyId);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 1950710..804550b 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -248,7 +248,7 @@
     // indicates whether the system maps all streams to a single stream.
     private final boolean mIsSingleVolume;
 
-    private boolean isPlatformVoice() {
+    /*package*/ boolean isPlatformVoice() {
         return mPlatformType == AudioSystem.PLATFORM_VOICE;
     }
 
@@ -2258,7 +2258,7 @@
     /** @see AudioManager#getDevicesForAttributes(AudioAttributes) */
     public @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributes(
             @NonNull AudioAttributes attributes) {
-        enforceModifyAudioRoutingPermission();
+        enforceQueryStateOrModifyRoutingPermission();
         return getDevicesForAttributesInt(attributes);
     }
 
@@ -2900,6 +2900,16 @@
         }
     }
 
+    private void enforceQueryStateOrModifyRoutingPermission() {
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+                != PackageManager.PERMISSION_GRANTED
+                && mContext.checkCallingOrSelfPermission(Manifest.permission.QUERY_AUDIO_STATE)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException(
+                    "Missing MODIFY_AUDIO_ROUTING or QUERY_AUDIO_STATE permissions");
+        }
+    }
+
     /** @see AudioManager#setVolumeIndexForAttributes(attr, int, int) */
     public void setVolumeIndexForAttributes(@NonNull AudioAttributes attr, int index, int flags,
                                             String callingPackage) {
@@ -3861,7 +3871,9 @@
      * @return true if microphone is reported as muted by primary HAL
      */
     public boolean isMicrophoneMuted() {
-        return mMicMuteFromSystemCached && !mMicMuteFromPrivacyToggle;
+        return mMicMuteFromSystemCached
+                && (!mMicMuteFromPrivacyToggle
+                        || mMicMuteFromApi || mMicMuteFromRestrictions || mMicMuteFromSwitch);
     }
 
     private boolean isMicrophoneSupposedToBeMuted() {
@@ -5814,7 +5826,7 @@
     public @AudioManager.DeviceVolumeBehavior
     int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
         // verify permissions
-        enforceModifyAudioRoutingPermission();
+        enforceQueryStateOrModifyRoutingPermission();
 
         // translate Java device type to native device type (for the devices masks for full / fixed)
         final int audioSystemDeviceOut = AudioDeviceInfo.convertDeviceTypeToInternalDevice(
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index 285f318..7296679 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -214,6 +214,13 @@
                 return;
             }
 
+            if (promptInfo.containsTestConfigurations()) {
+                if (getContext().checkCallingOrSelfPermission(TEST_BIOMETRIC)
+                        != PackageManager.PERMISSION_GRANTED) {
+                    checkInternalPermission();
+                }
+            }
+
             // Only allow internal clients to enable non-public options.
             if (promptInfo.containsPrivateApiConfigurations()) {
                 checkInternalPermission();
@@ -340,6 +347,20 @@
         }
 
         @Override
+        public void resetLockoutTimeBound(IBinder token, String opPackageName, int fromSensorId,
+                int userId, byte[] hardwareAuthToken) throws RemoteException {
+            checkInternalPermission();
+
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                mBiometricService.resetLockoutTimeBound(token, opPackageName, fromSensorId, userId,
+                        hardwareAuthToken);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         public CharSequence getButtonLabel(
                 int userId,
                 String opPackageName,
diff --git a/services/core/java/com/android/server/biometrics/AuthSession.java b/services/core/java/com/android/server/biometrics/AuthSession.java
index f888200..6017e92 100644
--- a/services/core/java/com/android/server/biometrics/AuthSession.java
+++ b/services/core/java/com/android/server/biometrics/AuthSession.java
@@ -195,7 +195,8 @@
             final int cookie = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1;
             final boolean requireConfirmation = isConfirmationRequired(sensor);
             sensor.goToStateWaitingForCookie(requireConfirmation, mToken, mOperationId,
-                    mUserId, mSensorReceiver, mOpPackageName, cookie);
+                    mUserId, mSensorReceiver, mOpPackageName, cookie,
+                    mPromptInfo.isAllowBackgroundAuthentication());
         }
     }
 
@@ -596,7 +597,8 @@
                     mPreAuthInfo.confirmationRequested,
                     FrameworkStatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED,
                     latency,
-                    mDebugEnabled);
+                    mDebugEnabled,
+                    -1 /* sensorId */);
         } else {
             final long latency = System.currentTimeMillis() - mStartTimeMs;
 
@@ -624,7 +626,8 @@
                     error,
                     0 /* vendorCode */,
                     mDebugEnabled,
-                    latency);
+                    latency,
+                    -1 /* sensorId */);
         }
     }
 
diff --git a/services/core/java/com/android/server/biometrics/BiometricSensor.java b/services/core/java/com/android/server/biometrics/BiometricSensor.java
index 85de81bb3..c9e148f 100644
--- a/services/core/java/com/android/server/biometrics/BiometricSensor.java
+++ b/services/core/java/com/android/server/biometrics/BiometricSensor.java
@@ -103,11 +103,12 @@
 
     void goToStateWaitingForCookie(boolean requireConfirmation, IBinder token, long sessionId,
             int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
-            int cookie)
+            int cookie, boolean allowBackgroundAuthentication)
             throws RemoteException {
         mCookie = cookie;
         impl.prepareForAuthentication(requireConfirmation, token,
-                sessionId, userId, sensorReceiver, opPackageName, mCookie);
+                sessionId, userId, sensorReceiver, opPackageName, mCookie,
+                allowBackgroundAuthentication);
         mSensorState = STATE_WAITING_FOR_COOKIE;
     }
 
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index a888209..63e7b4b 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -754,7 +754,7 @@
             }
         }
 
-        @Override
+        @Override // Binder call
         public void invalidateAuthenticatorIds(int userId, int fromSensorId,
                 IInvalidationCallback callback) {
             checkInternalPermission();
@@ -790,6 +790,45 @@
         }
 
         @Override // Binder call
+        public void resetLockoutTimeBound(IBinder token, String opPackageName, int fromSensorId,
+                int userId, byte[] hardwareAuthToken) {
+            checkInternalPermission();
+
+            // Check originating strength
+            if (!Utils.isAtLeastStrength(getSensorForId(fromSensorId).getCurrentStrength(),
+                    Authenticators.BIOMETRIC_STRONG)) {
+                Slog.w(TAG, "Sensor: " + fromSensorId + " is does not meet the required strength to"
+                        + " request resetLockout");
+                return;
+            }
+
+            // Request resetLockout for applicable sensors
+            for (BiometricSensor sensor : mSensors) {
+                if (sensor.id == fromSensorId) {
+                    continue;
+                }
+                try {
+                    final SensorPropertiesInternal props = sensor.impl
+                            .getSensorProperties(getContext().getOpPackageName());
+                    final boolean supportsChallengelessHat =
+                            props.resetLockoutRequiresHardwareAuthToken
+                            && !props.resetLockoutRequiresChallenge;
+                    final boolean doesNotRequireHat = !props.resetLockoutRequiresHardwareAuthToken;
+
+                    if (supportsChallengelessHat || doesNotRequireHat) {
+                        Slog.d(TAG, "resetLockout from: " + fromSensorId
+                                + ", for: " + sensor.id
+                                + ", userId: " + userId);
+                        sensor.impl.resetLockout(token, opPackageName, userId,
+                                hardwareAuthToken);
+                    }
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Remote exception", e);
+                }
+            }
+        }
+
+        @Override // Binder call
         public int getCurrentStrength(int sensorId) {
             checkInternalPermission();
 
@@ -1294,6 +1333,16 @@
         }
     }
 
+    @Nullable
+    private BiometricSensor getSensorForId(int sensorId) {
+        for (BiometricSensor sensor : mSensors) {
+            if (sensor.id == sensorId) {
+                return sensor;
+            }
+        }
+        return null;
+    }
+
     private void dumpInternal(PrintWriter pw) {
         pw.println("Sensors:");
         for (BiometricSensor sensor : mSensors) {
diff --git a/services/core/java/com/android/server/biometrics/PreAuthInfo.java b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
index 6851d71..ef43bc5 100644
--- a/services/core/java/com/android/server/biometrics/PreAuthInfo.java
+++ b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
@@ -23,6 +23,7 @@
 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.app.admin.DevicePolicyManager;
 import android.app.trust.ITrustManager;
 import android.hardware.biometrics.BiometricAuthenticator;
@@ -112,7 +113,8 @@
 
                 @AuthenticatorStatus int status = getStatusForBiometricAuthenticator(
                         devicePolicyManager, settingObserver, sensor, userId, opPackageName,
-                        checkDevicePolicyManager, requestedStrength, promptInfo.getSensorId());
+                        checkDevicePolicyManager, requestedStrength,
+                        promptInfo.getAllowedSensorIds());
 
                 Slog.d(TAG, "Package: " + opPackageName
                         + " Sensor ID: " + sensor.id
@@ -142,9 +144,10 @@
             DevicePolicyManager devicePolicyManager,
             BiometricService.SettingObserver settingObserver,
             BiometricSensor sensor, int userId, String opPackageName,
-            boolean checkDevicePolicyManager, int requestedStrength, int requestedSensorId) {
+            boolean checkDevicePolicyManager, int requestedStrength,
+            @NonNull List<Integer> requestedSensorIds) {
 
-        if (requestedSensorId != BiometricManager.SENSOR_ID_ANY && sensor.id != requestedSensorId) {
+        if (!requestedSensorIds.isEmpty() && !requestedSensorIds.contains(sensor.id)) {
             return BIOMETRIC_NO_HARDWARE;
         }
 
diff --git a/services/core/java/com/android/server/biometrics/Utils.java b/services/core/java/com/android/server/biometrics/Utils.java
index d9e21a8..f4cb387 100644
--- a/services/core/java/com/android/server/biometrics/Utils.java
+++ b/services/core/java/com/android/server/biometrics/Utils.java
@@ -176,7 +176,8 @@
      * @param requestedStrength the strength that it must meet
      * @return true only if the sensor is at least as strong as the requested strength
      */
-    public static boolean isAtLeastStrength(int sensorStrength, int requestedStrength) {
+    public static boolean isAtLeastStrength(@Authenticators.Types int sensorStrength,
+            @Authenticators.Types int requestedStrength) {
         // Clear out any bits that are not reserved for biometric
         sensorStrength &= Authenticators.BIOMETRIC_MIN_STRENGTH;
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index b31a54b..79e75b1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -26,6 +26,7 @@
 import android.content.pm.ApplicationInfo;
 import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.BiometricManager;
 import android.hardware.biometrics.BiometricsProtoEnums;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -50,10 +51,11 @@
     private final boolean mIsStrongBiometric;
     private final boolean mRequireConfirmation;
     private final ActivityTaskManager mActivityTaskManager;
+    private final BiometricManager mBiometricManager;
     @Nullable private final TaskStackListener mTaskStackListener;
     private final LockoutTracker mLockoutTracker;
     private final boolean mIsRestricted;
-    private final boolean mIsKeyguard;
+    private final boolean mAllowBackgroundAuthentication;
 
     protected final long mOperationId;
 
@@ -66,17 +68,18 @@
             int targetUserId, long operationId, boolean restricted, @NonNull String owner,
             int cookie, boolean requireConfirmation, int sensorId, boolean isStrongBiometric,
             int statsModality, int statsClient, @Nullable TaskStackListener taskStackListener,
-            @NonNull LockoutTracker lockoutTracker, boolean isKeyguard) {
+            @NonNull LockoutTracker lockoutTracker, boolean allowBackgroundAuthentication) {
         super(context, lazyDaemon, token, listener, targetUserId, owner, cookie, sensorId,
                 statsModality, BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient);
         mIsStrongBiometric = isStrongBiometric;
         mOperationId = operationId;
         mRequireConfirmation = requireConfirmation;
         mActivityTaskManager = ActivityTaskManager.getInstance();
+        mBiometricManager = context.getSystemService(BiometricManager.class);
         mTaskStackListener = taskStackListener;
         mLockoutTracker = lockoutTracker;
         mIsRestricted = restricted;
-        mIsKeyguard = isKeyguard;
+        mAllowBackgroundAuthentication = allowBackgroundAuthentication;
     }
 
     public @LockoutTracker.LockoutMode int handleFailedAttempt(int userId) {
@@ -117,7 +120,7 @@
     }
 
     public boolean isKeyguard() {
-        return mIsKeyguard;
+        return Utils.isKeyguard(getContext(), getOwnerString());
     }
 
     @Override
@@ -149,9 +152,15 @@
                 pm.incrementAuthForUser(getTargetUserId(), authenticated);
             }
 
+            if (mAllowBackgroundAuthentication) {
+                Slog.w(TAG, "Allowing background authentication,"
+                        + " this is allowed only for platform or test invocations");
+            }
+
             // Ensure authentication only succeeds if the client activity is on top.
             boolean isBackgroundAuth = false;
-            if (authenticated && !Utils.isKeyguard(getContext(), getOwnerString())
+            if (!mAllowBackgroundAuthentication && authenticated
+                    && !Utils.isKeyguard(getContext(), getOwnerString())
                     && !Utils.isSystem(getContext(), getOwnerString())) {
                 final List<ActivityManager.RunningTaskInfo> tasks =
                         mActivityTaskManager.getTasks(1);
@@ -207,6 +216,13 @@
                 for (int i = 0; i < hardwareAuthToken.size(); i++) {
                     byteToken[i] = hardwareAuthToken.get(i);
                 }
+
+                if (mIsStrongBiometric) {
+                    mBiometricManager.resetLockoutTimeBound(getToken(),
+                            getContext().getOpPackageName(),
+                            getSensorId(), getTargetUserId(), byteToken);
+                }
+
                 if (isBiometricPrompt() && listener != null) {
                     // BiometricService will add the token to keystore
                     listener.onAuthenticationSucceeded(getSensorId(), identifier, byteToken,
diff --git a/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java b/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java
index de57186..282261e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java
@@ -127,7 +127,8 @@
                 getContext().getPackageName(), mBiometricUtils, getSensorId(), mAuthenticatorIds);
         FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
                 mStatsModality,
-                BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_HAL);
+                BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_HAL,
+                -1 /* sensorId */);
         mCurrentTask.start(mRemoveCallback);
     }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java b/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java
index e3feb74..7f6903a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java
@@ -118,7 +118,8 @@
                     getTargetUserId(), identifier.getBiometricId());
             FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
                     mStatsModality,
-                    BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_FRAMEWORK);
+                    BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_FRAMEWORK,
+                    -1 /* sensorId */);
         }
         mEnrolledList.clear();
     }
diff --git a/services/core/java/com/android/server/biometrics/sensors/LoggableMonitor.java b/services/core/java/com/android/server/biometrics/sensors/LoggableMonitor.java
index edde3d4..4da644d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/LoggableMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/LoggableMonitor.java
@@ -126,7 +126,8 @@
                 mStatsClient,
                 acquiredInfo,
                 vendorCode,
-                Utils.isDebugEnabled(context, targetUserId));
+                Utils.isDebugEnabled(context, targetUserId),
+                -1 /* sensorId */);
     }
 
     protected final void logOnError(Context context, int error, int vendorCode, int targetUserId) {
@@ -164,7 +165,8 @@
                 error,
                 vendorCode,
                 Utils.isDebugEnabled(context, targetUserId),
-                sanitizeLatency(latency));
+                sanitizeLatency(latency),
+                -1 /* sensorId */);
     }
 
     protected final void logOnAuthenticated(Context context, boolean authenticated,
@@ -214,7 +216,8 @@
                 requireConfirmation,
                 authState,
                 sanitizeLatency(latency),
-                Utils.isDebugEnabled(context, targetUserId));
+                Utils.isDebugEnabled(context, targetUserId),
+                -1 /* sensorId */);
     }
 
     protected final void logOnEnrolled(int targetUserId, long latency, boolean enrollSuccessful) {
@@ -240,7 +243,8 @@
                 mStatsModality,
                 targetUserId,
                 sanitizeLatency(latency),
-                enrollSuccessful);
+                enrollSuccessful,
+                -1 /* sensorId */);
     }
 
     private long sanitizeLatency(long latency) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
index 06b049b..0002ad2 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
@@ -61,10 +61,10 @@
     @Override
     public void prepareForAuthentication(boolean requireConfirmation, IBinder token,
             long operationId, int userId, IBiometricSensorReceiver sensorReceiver,
-            String opPackageName, int cookie)
+            String opPackageName, int cookie, boolean allowBackgroundAuthentication)
             throws RemoteException {
         mFaceService.prepareForAuthentication(mSensorId, requireConfirmation, token, operationId,
-                userId, sensorReceiver, opPackageName, cookie);
+                userId, sensorReceiver, opPackageName, cookie, allowBackgroundAuthentication);
     }
 
     @Override
@@ -104,4 +104,11 @@
     public long getAuthenticatorId(int callingUserId) throws RemoteException {
         return mFaceService.getAuthenticatorId(mSensorId, callingUserId);
     }
+
+    @Override
+    public void resetLockout(IBinder token, String opPackageName, int userId,
+            byte[] hardwareAuthToken) throws RemoteException {
+        mFaceService.resetLockout(token, mSensorId, userId, hardwareAuthToken,
+                opPackageName);
+    }
 }
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
index 6dbd590..9f5dc69 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
@@ -306,7 +306,8 @@
         @Override // Binder call
         public void prepareForAuthentication(int sensorId, boolean requireConfirmation,
                 IBinder token, long operationId, int userId,
-                IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie) {
+                IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie,
+                boolean allowBackgroundAuthentication) {
             Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
 
             final ServiceProvider provider = getProviderForSensor(sensorId);
@@ -318,7 +319,7 @@
             final boolean restricted = true; // BiometricPrompt is always restricted
             provider.scheduleAuthenticate(sensorId, token, operationId, userId, cookie,
                     new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, restricted,
-                    BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, false /* isKeyguard */);
+                    BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, allowBackgroundAuthentication);
         }
 
         @Override // Binder call
@@ -393,14 +394,13 @@
                 final IFaceServiceReceiver receiver, final String opPackageName) {
             Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
 
-            final Pair<Integer, ServiceProvider> provider = getSingleProvider();
-            if (provider == null) {
-                Slog.w(TAG, "Null provider for removeAll");
-                return;
+            for (ServiceProvider provider : mServiceProviders) {
+                List<FaceSensorPropertiesInternal> props = provider.getSensorProperties();
+                for (FaceSensorPropertiesInternal prop : props) {
+                    provider.scheduleRemoveAll(prop.sensorId, token, userId, receiver,
+                            opPackageName);
+                }
             }
-
-            provider.second.scheduleRemoveAll(provider.first, token, userId, receiver,
-                    opPackageName);
         }
 
         @Override // Binder call
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
index 88edfbf..9b6fb0b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
@@ -103,7 +103,8 @@
 
     void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,
             int cookie, @NonNull ClientMonitorCallbackConverter callback,
-            @NonNull String opPackageName, boolean restricted, int statsClient, boolean isKeyguard);
+            @NonNull String opPackageName, boolean restricted, int statsClient,
+            boolean allowBackgroundAuthentication);
 
 
     void cancelAuthentication(int sensorId, @NonNull IBinder token);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
index 089cf1e..07d173c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
@@ -69,11 +69,11 @@
             @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
             boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId,
             boolean isStrongBiometric, int statsClient, @NonNull UsageStats usageStats,
-            @NonNull LockoutCache lockoutCache, boolean isKeyguard) {
+            @NonNull LockoutCache lockoutCache, boolean allowBackgroundAuthentication) {
         super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
                 owner, cookie, requireConfirmation, sensorId, isStrongBiometric,
                 BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */,
-                lockoutCache, isKeyguard);
+                lockoutCache, allowBackgroundAuthentication);
         mUsageStats = usageStats;
         mLockoutCache = lockoutCache;
         mNotificationManager = context.getSystemService(NotificationManager.class);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index 07a653f..ca29057 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -23,9 +23,11 @@
 import android.app.TaskStackListener;
 import android.content.Context;
 import android.content.pm.UserInfo;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.IInvalidationCallback;
 import android.hardware.biometrics.ITestSession;
 import android.hardware.biometrics.ITestSessionCallback;
+import android.hardware.biometrics.common.ComponentInfo;
 import android.hardware.biometrics.face.IFace;
 import android.hardware.biometrics.face.SensorProps;
 import android.hardware.face.Face;
@@ -134,10 +136,20 @@
         for (SensorProps prop : props) {
             final int sensorId = prop.commonProps.sensorId;
 
+            final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
+            if (prop.commonProps.componentInfo != null) {
+                for (ComponentInfo info : prop.commonProps.componentInfo) {
+                    componentInfo.add(new ComponentInfoInternal(info.componentId,
+                            info.hardwareVersion, info.firmwareVersion, info.serialNumber,
+                            info.softwareVersion));
+                }
+            }
+
             final FaceSensorPropertiesInternal internalProp = new FaceSensorPropertiesInternal(
                     prop.commonProps.sensorId, prop.commonProps.sensorStrength,
-                    prop.commonProps.maxEnrollmentsPerUser, false /* supportsFaceDetection */,
-                    prop.halControlsPreview, false /* resetLockoutRequiresChallenge */);
+                    prop.commonProps.maxEnrollmentsPerUser, componentInfo, prop.sensorType,
+                    false /* supportsFaceDetection */, prop.halControlsPreview,
+                    false /* resetLockoutRequiresChallenge */);
             final Sensor sensor = new Sensor(getTag() + "/" + sensorId, this, mContext, mHandler,
                     internalProp);
 
@@ -433,7 +445,7 @@
     public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
             int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback,
             @NonNull String opPackageName, boolean restricted, int statsClient,
-            boolean isKeyguard) {
+            boolean allowBackgroundAuthentication) {
         mHandler.post(() -> {
             final IFace daemon = getHalInstance();
             if (daemon == null) {
@@ -454,7 +466,8 @@
                         mContext, mSensors.get(sensorId).getLazySession(), token, callback, userId,
                         operationId, restricted, opPackageName, cookie,
                         false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient,
-                        mUsageStats, mSensors.get(sensorId).getLockoutCache(), isKeyguard);
+                        mUsageStats, mSensors.get(sensorId).getLockoutCache(),
+                        allowBackgroundAuthentication);
                 mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
             } catch (RemoteException e) {
                 Slog.e(getTag(), "Remote exception when scheduling authenticate", e);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
index 3434acb..c6f39aa 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
@@ -495,6 +495,15 @@
         Slog.w(mTag, "setTestHalEnabled: " + enabled);
         if (enabled != mTestHalEnabled) {
             // The framework should retrieve a new session from the HAL.
+            try {
+                if (mCurrentSession != null && mCurrentSession.mSession != null) {
+                    // TODO(181984005): This should be scheduled instead of directly invoked
+                    Slog.d(mTag, "Closing old session");
+                    mCurrentSession.mSession.close(888 /* cookie */);
+                }
+            } catch (RemoteException e) {
+                Slog.e(mTag, "RemoteException", e);
+            }
             mCurrentSession = null;
         }
         mTestHalEnabled = enabled;
@@ -519,6 +528,11 @@
             proto.end(userToken);
         }
 
+        proto.write(SensorStateProto.RESET_LOCKOUT_REQUIRES_HARDWARE_AUTH_TOKEN,
+                mSensorProperties.resetLockoutRequiresHardwareAuthToken);
+        proto.write(SensorStateProto.RESET_LOCKOUT_REQUIRES_CHALLENGE,
+                mSensorProperties.resetLockoutRequiresChallenge);
+
         proto.end(sensorToken);
     }
 
@@ -532,7 +546,8 @@
 
             FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
                     BiometricsProtoEnums.MODALITY_FACE,
-                    BiometricsProtoEnums.ISSUE_HAL_DEATH);
+                    BiometricsProtoEnums.ISSUE_HAL_DEATH,
+                    -1 /* sensorId */);
         }
 
         mScheduler.recordCrashState();
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
index afe7f24..50756c8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
@@ -27,11 +27,13 @@
 import android.hardware.biometrics.BiometricFaceConstants;
 import android.hardware.biometrics.BiometricManager;
 import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.ITestSession;
 import android.hardware.biometrics.ITestSessionCallback;
 import android.hardware.biometrics.face.V1_0.IBiometricsFace;
 import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback;
 import android.hardware.face.Face;
+import android.hardware.face.FaceSensorProperties;
 import android.hardware.face.FaceSensorPropertiesInternal;
 import android.hardware.face.IFaceServiceReceiver;
 import android.os.Binder;
@@ -332,8 +334,9 @@
             @NonNull BiometricScheduler scheduler) {
         mSensorProperties = new FaceSensorPropertiesInternal(sensorId,
                 Utils.authenticatorStrengthToPropertyStrength(strength),
-                maxTemplatesAllowed, false /* supportsFaceDetect */, supportsSelfIllumination,
-                true /* resetLockoutRequiresChallenge */);
+                maxTemplatesAllowed, new ArrayList<ComponentInfoInternal>() /* componentInfo */,
+                FaceSensorProperties.TYPE_UNKNOWN, false /* supportsFaceDetect */,
+                supportsSelfIllumination, true /* resetLockoutRequiresChallenge */);
         mContext = context;
         mSensorId = sensorId;
         mScheduler = scheduler;
@@ -384,7 +387,8 @@
 
                 FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
                         BiometricsProtoEnums.MODALITY_FACE,
-                        BiometricsProtoEnums.ISSUE_HAL_DEATH);
+                        BiometricsProtoEnums.ISSUE_HAL_DEATH,
+                        -1 /* sensorId */);
             }
 
             mScheduler.recordCrashState();
@@ -635,7 +639,7 @@
     public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
             int userId, int cookie, @NonNull ClientMonitorCallbackConverter receiver,
             @NonNull String opPackageName, boolean restricted, int statsClient,
-            boolean isKeyguard) {
+            boolean allowBackgroundAuthentication) {
         mHandler.post(() -> {
             scheduleUpdateActiveUserWithoutHandler(userId);
 
@@ -643,7 +647,7 @@
             final FaceAuthenticationClient client = new FaceAuthenticationClient(mContext,
                     mLazyDaemon, token, receiver, userId, operationId, restricted, opPackageName,
                     cookie, false /* requireConfirmation */, mSensorId, isStrongBiometric,
-                    statsClient, mLockoutTracker, mUsageStats, isKeyguard);
+                    statsClient, mLockoutTracker, mUsageStats, allowBackgroundAuthentication);
             mScheduler.scheduleClientMonitor(client);
         });
     }
@@ -798,6 +802,11 @@
             proto.end(userToken);
         }
 
+        proto.write(SensorStateProto.RESET_LOCKOUT_REQUIRES_HARDWARE_AUTH_TOKEN,
+                mSensorProperties.resetLockoutRequiresHardwareAuthToken);
+        proto.write(SensorStateProto.RESET_LOCKOUT_REQUIRES_CHALLENGE,
+                mSensorProperties.resetLockoutRequiresChallenge);
+
         proto.end(sensorToken);
     }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
index 3ca51d3..ff06a4a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
@@ -62,11 +62,11 @@
             @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
             boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId,
             boolean isStrongBiometric, int statsClient, @NonNull LockoutTracker lockoutTracker,
-            @NonNull UsageStats usageStats, boolean isKeyguard) {
+            @NonNull UsageStats usageStats, boolean allowBackgroundAuthentication) {
         super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
                 owner, cookie, requireConfirmation, sensorId, isStrongBiometric,
                 BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */,
-                lockoutTracker, isKeyguard);
+                lockoutTracker, allowBackgroundAuthentication);
         mUsageStats = usageStats;
 
         final Resources resources = getContext().getResources();
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/TestHal.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/TestHal.java
index 4cdb68d..84aa6d9 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/TestHal.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/TestHal.java
@@ -23,11 +23,11 @@
 import android.hardware.biometrics.face.V1_0.OptionalBool;
 import android.hardware.biometrics.face.V1_0.OptionalUint64;
 import android.hardware.biometrics.face.V1_0.Status;
-import android.os.NativeHandle;
 import android.os.RemoteException;
 import android.util.Slog;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 
 public class TestHal extends IBiometricsFace.Stub {
     private static final String TAG = "face.hidl.TestHal";
@@ -107,8 +107,12 @@
     }
 
     @Override
-    public int remove(int faceId) {
+    public int remove(int faceId) throws RemoteException {
         Slog.w(TAG, "remove");
+        if (mCallback != null) {
+            mCallback.onRemoved(0 /* deviceId */, new ArrayList<Integer>(Arrays.asList(faceId)),
+                    0 /* userId */);
+        }
         return 0;
     }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
index 32e9409..8109680 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
@@ -62,10 +62,10 @@
     @Override
     public void prepareForAuthentication(boolean requireConfirmation, IBinder token,
             long operationId, int userId, IBiometricSensorReceiver sensorReceiver,
-            String opPackageName, int cookie)
+            String opPackageName, int cookie, boolean allowBackgroundAuthentication)
             throws RemoteException {
         mFingerprintService.prepareForAuthentication(mSensorId, token, operationId, userId,
-                sensorReceiver, opPackageName, cookie);
+                sensorReceiver, opPackageName, cookie, allowBackgroundAuthentication);
     }
 
     @Override
@@ -105,4 +105,11 @@
     public long getAuthenticatorId(int callingUserId) throws RemoteException {
         return mFingerprintService.getAuthenticatorId(mSensorId, callingUserId);
     }
+
+    @Override
+    public void resetLockout(IBinder token, String opPackageName, int userId,
+            byte[] hardwareAuthToken) throws RemoteException {
+        mFingerprintService.resetLockout(token, mSensorId, userId, hardwareAuthToken,
+                opPackageName);
+    }
 }
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 396dd5f..e4397fd 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -315,7 +315,8 @@
                                     Slog.e(TAG, "Remote exception in negative button onClick()", e);
                                 }
                             })
-                    .setSensorId(props.sensorId)
+                    .setAllowedSensorIds(new ArrayList<>(
+                            Collections.singletonList(props.sensorId)))
                     .build();
 
             final BiometricPrompt.AuthenticationCallback promptCallback =
@@ -402,7 +403,7 @@
         @Override // Binder call
         public void prepareForAuthentication(int sensorId, IBinder token, long operationId,
                 int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
-                int cookie) {
+                int cookie, boolean allowBackgroundAuthentication) {
             Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
 
             final ServiceProvider provider = getProviderForSensor(sensorId);
@@ -414,7 +415,7 @@
             final boolean restricted = true; // BiometricPrompt is always restricted
             provider.scheduleAuthenticate(sensorId, token, operationId, userId, cookie,
                     new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, restricted,
-                    BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, false /* isKeyguard */);
+                    BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, allowBackgroundAuthentication);
         }
 
         @Override // Binder call
@@ -506,13 +507,13 @@
                 final IFingerprintServiceReceiver receiver, final String opPackageName) {
             Utils.checkPermission(getContext(), MANAGE_FINGERPRINT);
 
-            final Pair<Integer, ServiceProvider> provider = getSingleProvider();
-            if (provider == null) {
-                Slog.w(TAG, "Null provider for removeAll");
-                return;
+            for (ServiceProvider provider : mServiceProviders) {
+                List<FingerprintSensorPropertiesInternal> props = provider.getSensorProperties();
+                for (FingerprintSensorPropertiesInternal prop : props) {
+                    provider.scheduleRemoveAll(prop.sensorId, token, receiver, userId,
+                            opPackageName);
+                }
             }
-            provider.second.scheduleRemoveAll(provider.first, token, receiver, userId,
-                    opPackageName);
         }
 
         @Override // Binder call
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
index 0d50499..c09d2d3 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
@@ -96,7 +96,8 @@
 
     void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,
             int cookie, @NonNull ClientMonitorCallbackConverter callback,
-            @NonNull String opPackageName, boolean restricted, int statsClient, boolean isKeyguard);
+            @NonNull String opPackageName, boolean restricted, int statsClient,
+            boolean allowBackgroundAuthentication);
 
     void startPreparedClient(int sensorId, int cookie);
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index e2743f6..76a47d3 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -59,11 +59,12 @@
             boolean restricted, @NonNull String owner, int cookie, boolean requireConfirmation,
             int sensorId, boolean isStrongBiometric, int statsClient,
             @Nullable TaskStackListener taskStackListener, @NonNull LockoutCache lockoutCache,
-            @Nullable IUdfpsOverlayController udfpsOverlayController, boolean isKeyguard) {
+            @Nullable IUdfpsOverlayController udfpsOverlayController,
+            boolean allowBackgroundAuthentication) {
         super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted, owner,
                 cookie, requireConfirmation, sensorId, isStrongBiometric,
                 BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener,
-                lockoutCache, isKeyguard);
+                lockoutCache, allowBackgroundAuthentication);
         mLockoutCache = lockoutCache;
         mUdfpsOverlayController = udfpsOverlayController;
     }
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index d798198..1b5def6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -25,9 +25,11 @@
 import android.app.TaskStackListener;
 import android.content.Context;
 import android.content.pm.UserInfo;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.IInvalidationCallback;
 import android.hardware.biometrics.ITestSession;
 import android.hardware.biometrics.ITestSessionCallback;
+import android.hardware.biometrics.common.ComponentInfo;
 import android.hardware.biometrics.fingerprint.IFingerprint;
 import android.hardware.biometrics.fingerprint.SensorProps;
 import android.hardware.fingerprint.Fingerprint;
@@ -138,10 +140,20 @@
         for (SensorProps prop : props) {
             final int sensorId = prop.commonProps.sensorId;
 
+            final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
+            if (prop.commonProps.componentInfo != null) {
+                for (ComponentInfo info : prop.commonProps.componentInfo) {
+                    componentInfo.add(new ComponentInfoInternal(info.componentId,
+                            info.hardwareVersion, info.firmwareVersion, info.serialNumber,
+                            info.softwareVersion));
+                }
+            }
+
             final FingerprintSensorPropertiesInternal internalProp =
                     new FingerprintSensorPropertiesInternal(prop.commonProps.sensorId,
                             prop.commonProps.sensorStrength,
                             prop.commonProps.maxEnrollmentsPerUser,
+                            componentInfo,
                             prop.sensorType,
                             true /* resetLockoutRequiresHardwareAuthToken */);
             final Sensor sensor = new Sensor(getTag() + "/" + sensorId, this, mContext, mHandler,
@@ -457,7 +469,7 @@
     public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
             int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback,
             @NonNull String opPackageName, boolean restricted, int statsClient,
-            boolean isKeyguard) {
+            boolean allowBackgroundAuthentication) {
         mHandler.post(() -> {
             final IFingerprint daemon = getHalInstance();
             if (daemon == null) {
@@ -479,7 +491,7 @@
                         operationId, restricted, opPackageName, cookie,
                         false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient,
                         mTaskStackListener, mSensors.get(sensorId).getLockoutCache(),
-                        mUdfpsOverlayController, isKeyguard);
+                        mUdfpsOverlayController, allowBackgroundAuthentication);
                 mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
             } catch (RemoteException e) {
                 Slog.e(getTag(), "Remote exception when scheduling authenticate", e);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
index a98e7db..5631647 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
@@ -475,6 +475,15 @@
         Slog.w(mTag, "setTestHalEnabled: " + enabled);
         if (enabled != mTestHalEnabled) {
             // The framework should retrieve a new session from the HAL.
+            try {
+                if (mCurrentSession != null && mCurrentSession.mSession != null) {
+                    // TODO(181984005): This should be scheduled instead of directly invoked
+                    Slog.d(mTag, "Closing old session");
+                    mCurrentSession.mSession.close(999 /* cookie */);
+                }
+            } catch (RemoteException e) {
+                Slog.e(mTag, "RemoteException", e);
+            }
             mCurrentSession = null;
         }
         mTestHalEnabled = enabled;
@@ -499,6 +508,11 @@
             proto.end(userToken);
         }
 
+        proto.write(SensorStateProto.RESET_LOCKOUT_REQUIRES_HARDWARE_AUTH_TOKEN,
+                mSensorProperties.resetLockoutRequiresHardwareAuthToken);
+        proto.write(SensorStateProto.RESET_LOCKOUT_REQUIRES_CHALLENGE,
+                mSensorProperties.resetLockoutRequiresChallenge);
+
         proto.end(sensorToken);
     }
 
@@ -512,7 +526,8 @@
 
             FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
                     BiometricsProtoEnums.MODALITY_FINGERPRINT,
-                    BiometricsProtoEnums.ISSUE_HAL_DEATH);
+                    BiometricsProtoEnums.ISSUE_HAL_DEATH,
+                    -1 /* sensorId */);
         }
 
         mScheduler.recordCrashState();
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index 50fdc2e..f2992cc 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -28,6 +28,7 @@
 import android.hardware.biometrics.BiometricConstants;
 import android.hardware.biometrics.BiometricManager;
 import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.IInvalidationCallback;
 import android.hardware.biometrics.ITestSession;
 import android.hardware.biometrics.ITestSessionCallback;
@@ -355,7 +356,8 @@
 
         mSensorProperties = new FingerprintSensorPropertiesInternal(context, sensorId,
                 Utils.authenticatorStrengthToPropertyStrength(strength), maxEnrollmentsPerUser,
-                sensorType, resetLockoutRequiresHardwareAuthToken);
+                new ArrayList<ComponentInfoInternal>() /* componentInfo */, sensorType,
+                resetLockoutRequiresHardwareAuthToken);
     }
 
     public static Fingerprint21 newInstance(@NonNull Context context, int sensorId, int strength,
@@ -388,7 +390,8 @@
 
                 FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
                         BiometricsProtoEnums.MODALITY_FINGERPRINT,
-                        BiometricsProtoEnums.ISSUE_HAL_DEATH);
+                        BiometricsProtoEnums.ISSUE_HAL_DEATH,
+                        -1 /* sensorId */);
             }
 
             mScheduler.recordCrashState();
@@ -527,7 +530,9 @@
         // Fingerprint2.1 keeps track of lockout in the framework. Let's just do it on the handler
         // thread.
         mHandler.post(() -> {
-            mLockoutTracker.resetFailedAttemptsForUser(true /* clearAttemptCounter */, userId);
+            final FingerprintResetLockoutClient client = new FingerprintResetLockoutClient(mContext,
+                    userId, mContext.getOpPackageName(), sensorId, mLockoutTracker);
+            mScheduler.scheduleClientMonitor(client);
         });
     }
 
@@ -607,7 +612,7 @@
     public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
             int userId, int cookie, @NonNull ClientMonitorCallbackConverter listener,
             @NonNull String opPackageName, boolean restricted, int statsClient,
-            boolean isKeyguard) {
+            boolean allowBackgroundAuthentication) {
         mHandler.post(() -> {
             scheduleUpdateActiveUserWithoutHandler(userId);
 
@@ -616,7 +621,8 @@
                     mContext, mLazyDaemon, token, listener, userId, operationId, restricted,
                     opPackageName, cookie, false /* requireConfirmation */,
                     mSensorProperties.sensorId, isStrongBiometric, statsClient,
-                    mTaskStackListener, mLockoutTracker, mUdfpsOverlayController, isKeyguard);
+                    mTaskStackListener, mLockoutTracker, mUdfpsOverlayController,
+                    allowBackgroundAuthentication);
             mScheduler.scheduleClientMonitor(client);
         });
     }
@@ -759,6 +765,11 @@
             proto.end(userToken);
         }
 
+        proto.write(SensorStateProto.RESET_LOCKOUT_REQUIRES_HARDWARE_AUTH_TOKEN,
+                mSensorProperties.resetLockoutRequiresHardwareAuthToken);
+        proto.write(SensorStateProto.RESET_LOCKOUT_REQUIRES_CHALLENGE,
+                mSensorProperties.resetLockoutRequiresChallenge);
+
         proto.end(sensorToken);
     }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
index 2394a70..90c4b4a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
@@ -22,6 +22,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.hardware.biometrics.BiometricManager;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.fingerprint.FingerprintManager;
 import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
 import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
@@ -421,6 +422,7 @@
                 .getInteger(R.integer.config_fingerprintMaxTemplatesPerUser);
         mSensorProperties = new FingerprintSensorPropertiesInternal(sensorId,
                 Utils.authenticatorStrengthToPropertyStrength(strength), maxTemplatesAllowed,
+                new ArrayList<ComponentInfoInternal>() /* componentInfo */,
                 FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
                 resetLockoutRequiresHardwareAuthToken);
         mMockHalResultController = controller;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
index db37112..97f1287 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
@@ -59,11 +59,12 @@
             int sensorId, boolean isStrongBiometric, int statsClient,
             @NonNull TaskStackListener taskStackListener,
             @NonNull LockoutFrameworkImpl lockoutTracker,
-            @Nullable IUdfpsOverlayController udfpsOverlayController, boolean isKeyguard) {
+            @Nullable IUdfpsOverlayController udfpsOverlayController,
+            boolean allowBackgroundAuthentication) {
         super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
                 owner, cookie, requireConfirmation, sensorId, isStrongBiometric,
                 BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener,
-                lockoutTracker, isKeyguard);
+                lockoutTracker, allowBackgroundAuthentication);
         mLockoutFrameworkImpl = lockoutTracker;
         mUdfpsOverlayController = udfpsOverlayController;
     }
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintResetLockoutClient.java
new file mode 100644
index 0000000..a39f4f8
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintResetLockoutClient.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 com.android.server.biometrics.sensors.fingerprint.hidl;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.biometrics.BiometricsProtoEnums;
+
+import com.android.server.biometrics.BiometricsProto;
+import com.android.server.biometrics.sensors.BaseClientMonitor;
+
+/**
+ * Clears lockout, which is handled in the framework (and not the HAL) for the
+ * IBiometricsFingerprint@2.1 interface.
+ */
+public class FingerprintResetLockoutClient extends BaseClientMonitor {
+
+    @NonNull final LockoutFrameworkImpl mLockoutTracker;
+
+    public FingerprintResetLockoutClient(@NonNull Context context, int userId,
+            @NonNull String owner, int sensorId, @NonNull LockoutFrameworkImpl lockoutTracker) {
+        super(context, null /* token */, null /* listener */, userId, owner, 0 /* cookie */,
+                sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN,
+                BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
+        mLockoutTracker = lockoutTracker;
+    }
+
+    @Override
+    public void start(@NonNull Callback callback) {
+        super.start(callback);
+        mLockoutTracker.resetFailedAttemptsForUser(true /* clearAttemptCounter */,
+                getTargetUserId());
+        callback.onClientFinished(this, true /* success */);
+    }
+
+    @Override
+    public int getProtoEnum() {
+        return BiometricsProto.CM_RESET_LOCKOUT;
+    }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/TestHal.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/TestHal.java
index 14fdb50..129f6a6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/TestHal.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/TestHal.java
@@ -93,8 +93,11 @@
     }
 
     @Override
-    public int remove(int gid, int fid) {
+    public int remove(int gid, int fid) throws RemoteException {
         Slog.w(TAG, "Remove");
+        if (mCallback != null) {
+            mCallback.onRemoved(0 /* deviceId */, fid, gid, 0 /* remaining */);
+        }
         return 0;
     }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java
index f44e069..1003c26 100644
--- a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java
@@ -59,7 +59,8 @@
     @Override
     public void prepareForAuthentication(boolean requireConfirmation, IBinder token,
             long sessionId, int userId, IBiometricSensorReceiver sensorReceiver,
-            String opPackageName, int cookie) throws RemoteException {
+            String opPackageName, int cookie, boolean allowBackgroundAuthentication)
+            throws RemoteException {
     }
 
     @Override
@@ -95,4 +96,9 @@
     public long getAuthenticatorId(int callingUserId) throws RemoteException {
         return 0;
     }
+
+    @Override
+    public void resetLockout(IBinder token, String opPackageName, int userId,
+            byte[] hardwareAuthToken) throws RemoteException {
+    }
 }
\ No newline at end of file
diff --git a/services/core/java/com/android/server/connectivity/ConnectivityConstants.java b/services/core/java/com/android/server/connectivity/ConnectivityConstants.java
index 0fb6fec..325a2cd 100644
--- a/services/core/java/com/android/server/connectivity/ConnectivityConstants.java
+++ b/services/core/java/com/android/server/connectivity/ConnectivityConstants.java
@@ -18,18 +18,10 @@
 
 /**
  * A class encapsulating various constants used by Connectivity.
+ * TODO : remove this class.
  * @hide
  */
 public class ConnectivityConstants {
-
-    // Penalty applied to scores of Networks that have not been validated.
-    public static final int UNVALIDATED_SCORE_PENALTY = 40;
-
-    // Score for explicitly connected network.
-    //
-    // This ensures that a) the explicitly selected network is never trumped by anything else, and
-    // b) the explicitly selected network is never torn down.
-    public static final int EXPLICITLY_SELECTED_NETWORK_SCORE = 100;
     // VPNs typically have priority over other networks. Give them a score that will
     // let them win every single time.
     public static final int VPN_DEFAULT_SCORE = 101;
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index 702434b..ffeb77d 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -18,15 +18,15 @@
 
 import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
 import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
+import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_MAX_SAMPLES;
+import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_MIN_SAMPLES;
+import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS;
+import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_DEFAULT_MODE;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_SPECIFIER;
 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;
-import static android.provider.Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT;
-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;
 
 import android.annotation.NonNull;
 import android.content.ContentResolver;
diff --git a/services/core/java/com/android/server/connectivity/FullScore.java b/services/core/java/com/android/server/connectivity/FullScore.java
new file mode 100644
index 0000000..028cfee
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/FullScore.java
@@ -0,0 +1,211 @@
+/*
+ * 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 static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.net.NetworkAgentConfig;
+import android.net.NetworkCapabilities;
+import android.net.NetworkScore;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.StringJoiner;
+
+/**
+ * This class represents how desirable a network is.
+ *
+ * FullScore is very similar to NetworkScore, but it contains the bits that are managed
+ * by ConnectivityService. This provides static guarantee that all users must know whether
+ * they are handling a score that had the CS-managed bits set.
+ */
+public class FullScore {
+    // This will be removed soon. Do *NOT* depend on it for any new code that is not part of
+    // a migration.
+    private final int mLegacyInt;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"POLICY_"}, value = {
+            POLICY_IS_VALIDATED,
+            POLICY_IS_VPN,
+            POLICY_EVER_USER_SELECTED,
+            POLICY_ACCEPT_UNVALIDATED
+    })
+    public @interface Policy {
+    }
+
+    // Agent-managed policies are in NetworkScore. They start from 1.
+    // CS-managed policies, counting from 63 downward
+    // This network is validated. CS-managed because the source of truth is in NetworkCapabilities.
+    /** @hide */
+    public static final int POLICY_IS_VALIDATED = 63;
+
+    // This is a VPN and behaves as one for scoring purposes.
+    /** @hide */
+    public static final int POLICY_IS_VPN = 62;
+
+    // This network has been selected by the user manually from settings or a 3rd party app
+    // at least once. {@see NetworkAgentConfig#explicitlySelected}.
+    /** @hide */
+    public static final int POLICY_EVER_USER_SELECTED = 61;
+
+    // The user has indicated in UI that this network should be used even if it doesn't
+    // validate. {@see NetworkAgentConfig#acceptUnvalidated}.
+    /** @hide */
+    public static final int POLICY_ACCEPT_UNVALIDATED = 60;
+
+    // To help iterate when printing
+    @VisibleForTesting
+    static final int MIN_CS_MANAGED_POLICY = POLICY_ACCEPT_UNVALIDATED;
+    @VisibleForTesting
+    static final int MAX_CS_MANAGED_POLICY = POLICY_IS_VALIDATED;
+
+    @VisibleForTesting
+    static @NonNull String policyNameOf(final int policy) {
+        switch (policy) {
+            case POLICY_IS_VALIDATED: return "IS_VALIDATED";
+            case POLICY_IS_VPN: return "IS_VPN";
+            case POLICY_EVER_USER_SELECTED: return "EVER_USER_SELECTED";
+            case POLICY_ACCEPT_UNVALIDATED: return "ACCEPT_UNVALIDATED";
+        }
+        throw new IllegalArgumentException("Unknown policy : " + policy);
+    }
+
+    // Bitmask of all the policies applied to this score.
+    private final long mPolicies;
+
+    FullScore(final int legacyInt, final long policies) {
+        mLegacyInt = legacyInt;
+        mPolicies = policies;
+    }
+
+    /**
+     * Given a score supplied by the NetworkAgent and CS-managed objects, produce a full score.
+     *
+     * @param score the score supplied by the agent
+     * @param caps the NetworkCapabilities of the network
+     * @param config the NetworkAgentConfig of the network
+     * @return an FullScore that is appropriate to use for ranking.
+     */
+    public static FullScore fromNetworkScore(@NonNull final NetworkScore score,
+            @NonNull final NetworkCapabilities caps, @NonNull final NetworkAgentConfig config) {
+        return withPolicies(score.getLegacyInt(), caps.hasCapability(NET_CAPABILITY_VALIDATED),
+                caps.hasTransport(TRANSPORT_VPN),
+                config.explicitlySelected,
+                config.acceptUnvalidated);
+    }
+
+    /**
+     * Return a new score given updated caps and config.
+     *
+     * @param caps the NetworkCapabilities of the network
+     * @param config the NetworkAgentConfig of the network
+     * @return a score with the policies from the arguments reset
+     */
+    public FullScore mixInScore(@NonNull final NetworkCapabilities caps,
+            @NonNull final NetworkAgentConfig config) {
+        return withPolicies(mLegacyInt, caps.hasCapability(NET_CAPABILITY_VALIDATED),
+                caps.hasTransport(TRANSPORT_VPN),
+                config.explicitlySelected,
+                config.acceptUnvalidated);
+    }
+
+    private static FullScore withPolicies(@NonNull final int legacyInt,
+            final boolean isValidated,
+            final boolean isVpn,
+            final boolean everUserSelected,
+            final boolean acceptUnvalidated) {
+        return new FullScore(legacyInt,
+                (isValidated         ? 1L << POLICY_IS_VALIDATED : 0)
+                | (isVpn             ? 1L << POLICY_IS_VPN : 0)
+                | (everUserSelected  ? 1L << POLICY_EVER_USER_SELECTED : 0)
+                | (acceptUnvalidated ? 1L << POLICY_ACCEPT_UNVALIDATED : 0));
+    }
+
+    /**
+     * For backward compatibility, get the legacy int.
+     * This will be removed before S is published.
+     */
+    public int getLegacyInt() {
+        return getLegacyInt(false /* pretendValidated */);
+    }
+
+    public int getLegacyIntAsValidated() {
+        return getLegacyInt(true /* pretendValidated */);
+    }
+
+    // TODO : remove these two constants
+    // Penalty applied to scores of Networks that have not been validated.
+    private static final int UNVALIDATED_SCORE_PENALTY = 40;
+
+    // Score for a network that can be used unvalidated
+    private static final int ACCEPT_UNVALIDATED_NETWORK_SCORE = 100;
+
+    private int getLegacyInt(boolean pretendValidated) {
+        // If the user has chosen this network at least once, give it the maximum score when
+        // checking to pretend it's validated, or if it doesn't need to validate because the
+        // user said to use it even if it doesn't validate.
+        // This ensures that networks that have been selected in UI are not torn down before the
+        // user gets a chance to prefer it when a higher-scoring network (e.g., Ethernet) is
+        // available.
+        if (hasPolicy(POLICY_EVER_USER_SELECTED)
+                && (hasPolicy(POLICY_ACCEPT_UNVALIDATED) || pretendValidated)) {
+            return ACCEPT_UNVALIDATED_NETWORK_SCORE;
+        }
+
+        int score = mLegacyInt;
+        // Except for VPNs, networks are subject to a penalty for not being validated.
+        // Apply the penalty unless the network is a VPN, or it's validated or pretending to be.
+        if (!hasPolicy(POLICY_IS_VALIDATED) && !pretendValidated && !hasPolicy(POLICY_IS_VPN)) {
+            score -= UNVALIDATED_SCORE_PENALTY;
+        }
+        if (score < 0) score = 0;
+        return score;
+    }
+
+    /**
+     * @return whether this score has a particular policy.
+     */
+    @VisibleForTesting
+    public boolean hasPolicy(final int policy) {
+        return 0 != (mPolicies & (1L << policy));
+    }
+
+    // Example output :
+    // Score(50 ; Policies : EVER_USER_SELECTED&IS_VALIDATED)
+    @Override
+    public String toString() {
+        final StringJoiner sj = new StringJoiner(
+                "&", // delimiter
+                "Score(" + mLegacyInt + " ; Policies : ", // prefix
+                ")"); // suffix
+        for (int i = NetworkScore.MIN_AGENT_MANAGED_POLICY;
+                i <= NetworkScore.MAX_AGENT_MANAGED_POLICY; ++i) {
+            if (hasPolicy(i)) sj.add(policyNameOf(i));
+        }
+        for (int i = MIN_CS_MANAGED_POLICY; i <= MAX_CS_MANAGED_POLICY; ++i) {
+            if (hasPolicy(i)) sj.add(policyNameOf(i));
+        }
+        return sj.toString();
+    }
+}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index e44dcf5..103ab95 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -25,6 +25,8 @@
 import android.net.CaptivePortalData;
 import android.net.IDnsResolver;
 import android.net.INetd;
+import android.net.INetworkAgent;
+import android.net.INetworkAgentRegistry;
 import android.net.INetworkMonitor;
 import android.net.LinkProperties;
 import android.net.NattKeepalivePacketData;
@@ -51,8 +53,6 @@
 import android.util.Pair;
 import android.util.SparseArray;
 
-import com.android.connectivity.aidl.INetworkAgent;
-import com.android.connectivity.aidl.INetworkAgentRegistry;
 import com.android.internal.util.WakeupMessage;
 import com.android.server.ConnectivityService;
 
@@ -303,8 +303,9 @@
     // validated).
     private boolean mInactive;
 
-    // This represents the quality of the network.
-    private NetworkScore mScore;
+    // This represents the quality of the network. As opposed to NetworkScore, FullScore includes
+    // the ConnectivityService-managed bits.
+    private FullScore mScore;
 
     // The list of NetworkRequests being satisfied by this Network.
     private final SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<>();
@@ -356,12 +357,12 @@
         networkInfo = info;
         linkProperties = lp;
         networkCapabilities = nc;
-        mScore = score;
+        networkAgentConfig = config;
+        setScore(score); // uses members networkCapabilities and networkAgentConfig
         clatd = new Nat464Xlat(this, netd, dnsResolver, deps);
         mConnService = connService;
         mContext = context;
         mHandler = handler;
-        networkAgentConfig = config;
         this.factorySerialNumber = factorySerialNumber;
         this.creatorUid = creatorUid;
         mQosCallbackTracker = qosCallbackTracker;
@@ -667,6 +668,7 @@
             @NonNull final NetworkCapabilities nc) {
         final NetworkCapabilities oldNc = networkCapabilities;
         networkCapabilities = nc;
+        mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig);
         final NetworkMonitorManager nm = mNetworkMonitor;
         if (nm != null) {
             nm.notifyNetworkCapabilitiesChanged(nc);
@@ -844,30 +846,6 @@
         return isVPN();
     }
 
-    private int getCurrentScore(boolean pretendValidated) {
-        // TODO: We may want to refactor this into a NetworkScore class that takes a base score from
-        // the NetworkAgent and signals from the NetworkAgent and uses those signals to modify the
-        // score.  The NetworkScore class would provide a nice place to centralize score constants
-        // so they are not scattered about the transports.
-
-        // If this network is explicitly selected and the user has decided to use it even if it's
-        // unvalidated, give it the maximum score. Also give it the maximum score if it's explicitly
-        // selected and we're trying to see what its score could be. This ensures that we don't tear
-        // down an explicitly selected network before the user gets a chance to prefer it when
-        // a higher-scoring network (e.g., Ethernet) is available.
-        if (networkAgentConfig.explicitlySelected
-                && (networkAgentConfig.acceptUnvalidated || pretendValidated)) {
-            return ConnectivityConstants.EXPLICITLY_SELECTED_NETWORK_SCORE;
-        }
-
-        int score = mScore.getLegacyInt();
-        if (!lastValidated && !pretendValidated && !ignoreWifiUnvalidationPenalty() && !isVPN()) {
-            score -= ConnectivityConstants.UNVALIDATED_SCORE_PENALTY;
-        }
-        if (score < 0) score = 0;
-        return score;
-    }
-
     // Return true on devices configured to ignore score penalty for wifi networks
     // that become unvalidated (b/31075769).
     private boolean ignoreWifiUnvalidationPenalty() {
@@ -880,17 +858,29 @@
     // Get the current score for this Network.  This may be modified from what the
     // NetworkAgent sent, as it has modifiers applied to it.
     public int getCurrentScore() {
-        return getCurrentScore(false);
+        return mScore.getLegacyInt();
     }
 
     // Get the current score for this Network as if it was validated.  This may be modified from
     // what the NetworkAgent sent, as it has modifiers applied to it.
     public int getCurrentScoreAsValidated() {
-        return getCurrentScore(true);
+        return mScore.getLegacyIntAsValidated();
     }
 
+    /**
+     * Mix-in the ConnectivityService-managed bits in the score.
+     */
     public void setScore(final NetworkScore score) {
-        mScore = score;
+        mScore = FullScore.fromNetworkScore(score, networkCapabilities, networkAgentConfig);
+    }
+
+    /**
+     * Update the ConnectivityService-managed bits in the score.
+     *
+     * Call this after updating the network agent config.
+     */
+    public void updateScoreForNetworkAgentConfigUpdate() {
+        mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig);
     }
 
     /**
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 508739f..0c0d459 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -28,6 +28,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
+import android.graphics.drawable.Icon;
+import android.net.ConnectivityResources;
 import android.net.NetworkSpecifier;
 import android.net.TelephonyNetworkSpecifier;
 import android.net.wifi.WifiInfo;
@@ -40,7 +42,7 @@
 import android.util.SparseIntArray;
 import android.widget.Toast;
 
-import com.android.internal.R;
+import com.android.connectivity.resources.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 
@@ -82,6 +84,7 @@
 
     // The context is for the current user (system server)
     private final Context mContext;
+    private final Resources mResources;
     private final TelephonyManager mTelephonyManager;
     // The notification manager is created from a context for User.ALL, so notifications
     // will be sent to all users.
@@ -96,6 +99,7 @@
                 (NotificationManager) c.createContextAsUser(UserHandle.ALL, 0 /* flags */)
                         .getSystemService(Context.NOTIFICATION_SERVICE);
         mNotificationTypeMap = new SparseIntArray();
+        mResources = new ConnectivityResources(mContext).get();
     }
 
     @VisibleForTesting
@@ -113,20 +117,19 @@
         return -1;
     }
 
-    private static String getTransportName(final int transportType) {
-        Resources r = Resources.getSystem();
-        String[] networkTypes = r.getStringArray(R.array.network_switch_type_name);
+    private String getTransportName(final int transportType) {
+        String[] networkTypes = mResources.getStringArray(R.array.network_switch_type_name);
         try {
             return networkTypes[transportType];
         } catch (IndexOutOfBoundsException e) {
-            return r.getString(R.string.network_switch_type_name_unknown);
+            return mResources.getString(R.string.network_switch_type_name_unknown);
         }
     }
 
     private static int getIcon(int transportType) {
         return (transportType == TRANSPORT_WIFI)
-                ? R.drawable.stat_notify_wifi_in_range :  // TODO: Distinguish ! from ?.
-                R.drawable.stat_notify_rssi_in_range;
+                ? R.drawable.stat_notify_wifi_in_range  // TODO: Distinguish ! from ?.
+                : R.drawable.stat_notify_rssi_in_range;
     }
 
     /**
@@ -156,7 +159,7 @@
         final String tag = tagFor(id);
         final int eventId = notifyType.eventId;
         final int transportType;
-        final String name;
+        final CharSequence name;
         if (nai != null) {
             transportType = approximateTransportType(nai);
             final String extraInfo = nai.networkInfo.getExtraInfo();
@@ -194,10 +197,10 @@
                     tag, nameOf(eventId), getTransportName(transportType), name, highPriority));
         }
 
-        Resources r = mContext.getResources();
+        final Resources r = mResources;
         final CharSequence title;
         final CharSequence details;
-        int icon = getIcon(transportType);
+        Icon icon = Icon.createWithResource(r, getIcon(transportType));
         if (notifyType == NotificationType.NO_INTERNET && transportType == TRANSPORT_WIFI) {
             title = r.getString(R.string.wifi_no_internet, name);
             details = r.getString(R.string.wifi_no_internet_detailed);
@@ -272,8 +275,7 @@
                 .setSmallIcon(icon)
                 .setAutoCancel(true)
                 .setTicker(title)
-                .setColor(mContext.getColor(
-                        com.android.internal.R.color.system_notification_accent_color))
+                .setColor(mContext.getColor(android.R.color.system_notification_accent_color))
                 .setContentTitle(title)
                 .setContentIntent(intent)
                 .setLocalOnly(true)
@@ -353,7 +355,7 @@
     public void showToast(NetworkAgentInfo fromNai, NetworkAgentInfo toNai) {
         String fromTransport = getTransportName(approximateTransportType(fromNai));
         String toTransport = getTransportName(approximateTransportType(toNai));
-        String text = mContext.getResources().getString(
+        String text = mResources.getString(
                 R.string.network_switch_metered_toast, fromTransport, toTransport);
         Toast.makeText(mContext, text, Toast.LENGTH_LONG).show();
     }
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
index 8b9c836..f572b46 100644
--- a/services/core/java/com/android/server/connectivity/ProxyTracker.java
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -16,10 +16,10 @@
 
 package com.android.server.connectivity;
 
-import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST;
-import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_HOST;
-import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_PAC;
-import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_PORT;
+import static android.net.ConnectivitySettingsManager.GLOBAL_HTTP_PROXY_EXCLUSION_LIST;
+import static android.net.ConnectivitySettingsManager.GLOBAL_HTTP_PROXY_HOST;
+import static android.net.ConnectivitySettingsManager.GLOBAL_HTTP_PROXY_PAC;
+import static android.net.ConnectivitySettingsManager.GLOBAL_HTTP_PROXY_PORT;
 import static android.provider.Settings.Global.HTTP_PROXY;
 
 import android.annotation.NonNull;
@@ -34,7 +34,6 @@
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Handler;
-import android.os.HandlerExecutor;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
@@ -105,7 +104,7 @@
 
         PacProxyInstalledListener listener = new PacProxyInstalledListener(pacChangedEvent);
         mPacProxyManager.addPacProxyInstalledListener(
-                new HandlerExecutor(mConnectivityServiceHandler), listener);
+                mConnectivityServiceHandler::post, listener);
     }
 
     // Convert empty ProxyInfo's to null as null-checks are used to determine if proxies are present
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 2e61ae1..a4df43c 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -23,6 +23,7 @@
 import static android.net.RouteInfo.RTN_UNREACHABLE;
 import static android.net.VpnManager.NOTIFICATION_CHANNEL_VPN;
 import static android.os.PowerWhitelistManager.REASON_VPN;
+import static android.os.UserHandle.PER_USER_RANGE;
 
 import static com.android.internal.util.Preconditions.checkArgument;
 import static com.android.internal.util.Preconditions.checkNotNull;
@@ -69,8 +70,8 @@
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkProvider;
 import android.net.NetworkRequest;
+import android.net.NetworkScore;
 import android.net.RouteInfo;
-import android.net.UidRange;
 import android.net.UidRangeParcel;
 import android.net.UnderlyingNetworkInfo;
 import android.net.VpnManager;
@@ -223,7 +224,7 @@
     protected NetworkAgent mNetworkAgent;
     private final Looper mLooper;
     @VisibleForTesting
-    protected final NetworkCapabilities mNetworkCapabilities;
+    protected NetworkCapabilities mNetworkCapabilities;
     private final SystemServices mSystemServices;
     private final Ikev2SessionCreator mIkev2SessionCreator;
     private final UserManager mUserManager;
@@ -460,11 +461,12 @@
         mLegacyState = LegacyVpnInfo.STATE_DISCONNECTED;
         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0 /* subtype */, NETWORKTYPE,
                 "" /* subtypeName */);
-        mNetworkCapabilities = new NetworkCapabilities();
-        mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN);
-        mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
-        mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
-        mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE));
+        mNetworkCapabilities = new NetworkCapabilities.Builder()
+                .addTransportType(NetworkCapabilities.TRANSPORT_VPN)
+                .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
+                .setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE))
+                .build();
 
         loadAlwaysOnPackage();
     }
@@ -525,8 +527,10 @@
     }
 
     private void resetNetworkCapabilities() {
-        mNetworkCapabilities.setUids(null);
-        mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE));
+        mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities)
+                .setUids(null)
+                .setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE))
+                .build();
     }
 
     /**
@@ -1176,11 +1180,13 @@
 
         if (!allowIPv4) {
             lp.addRoute(new RouteInfo(new IpPrefix(
-                    NetworkStackConstants.IPV4_ADDR_ANY, 0), RTN_UNREACHABLE));
+                    NetworkStackConstants.IPV4_ADDR_ANY, 0), null /*gateway*/,
+                    null /*iface*/, RTN_UNREACHABLE));
         }
         if (!allowIPv6) {
             lp.addRoute(new RouteInfo(new IpPrefix(
-                    NetworkStackConstants.IPV6_ADDR_ANY, 0), RTN_UNREACHABLE));
+                    NetworkStackConstants.IPV6_ADDR_ANY, 0), null /*gateway*/,
+                    null /*iface*/, RTN_UNREACHABLE));
         }
 
         // Concatenate search domains into a string.
@@ -1236,33 +1242,38 @@
         // registered with registerDefaultNetworkCallback. This in turn protects the invariant
         // that an app calling ConnectivityManager#bindProcessToNetwork(getDefaultNetwork())
         // behaves the same as when it uses the default network.
-        mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+        final NetworkCapabilities.Builder capsBuilder =
+                new NetworkCapabilities.Builder(mNetworkCapabilities);
+        capsBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
 
         mLegacyState = LegacyVpnInfo.STATE_CONNECTING;
         updateState(DetailedState.CONNECTING, "agentConnect");
 
-        NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig();
+        NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig.Builder().build();
         networkAgentConfig.allowBypass = mConfig.allowBypass && !mLockdown;
 
-        mNetworkCapabilities.setOwnerUid(mOwnerUID);
-        mNetworkCapabilities.setAdministratorUids(new int[] {mOwnerUID});
-        mNetworkCapabilities.setUids(createUserAndRestrictedProfilesRanges(mUserId,
+        capsBuilder.setOwnerUid(mOwnerUID);
+        capsBuilder.setAdministratorUids(new int[] {mOwnerUID});
+        capsBuilder.setUids(createUserAndRestrictedProfilesRanges(mUserId,
                 mConfig.allowedApplications, mConfig.disallowedApplications));
 
-        mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(getActiveVpnType()));
+        capsBuilder.setTransportInfo(new VpnTransportInfo(getActiveVpnType()));
 
         // Only apps targeting Q and above can explicitly declare themselves as metered.
         // These VPNs are assumed metered unless they state otherwise.
         if (mIsPackageTargetingAtLeastQ && mConfig.isMetered) {
-            mNetworkCapabilities.removeCapability(NET_CAPABILITY_NOT_METERED);
+            capsBuilder.removeCapability(NET_CAPABILITY_NOT_METERED);
         } else {
-            mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
+            capsBuilder.addCapability(NET_CAPABILITY_NOT_METERED);
         }
 
+        mNetworkCapabilities = capsBuilder.build();
         mNetworkAgent = new NetworkAgent(mContext, mLooper, NETWORKTYPE /* logtag */,
-                mNetworkCapabilities, lp, VPN_DEFAULT_SCORE, networkAgentConfig, mNetworkProvider) {
+                mNetworkCapabilities, lp,
+                new NetworkScore.Builder().setLegacyInt(VPN_DEFAULT_SCORE).build(),
+                networkAgentConfig, mNetworkProvider) {
             @Override
-            public void unwanted() {
+            public void onNetworkUnwanted() {
                 // We are user controlled, not driven by NetworkRequest.
             }
         };
@@ -1348,7 +1359,7 @@
         String oldInterface = mInterface;
         Connection oldConnection = mConnection;
         NetworkAgent oldNetworkAgent = mNetworkAgent;
-        Set<UidRange> oldUsers = mNetworkCapabilities.getUids();
+        Set<Range<Integer>> oldUsers = mNetworkCapabilities.getUids();
 
         // Configure the interface. Abort if any of these steps fails.
         ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu));
@@ -1423,7 +1434,8 @@
             // restore old state
             mConfig = oldConfig;
             mConnection = oldConnection;
-            mNetworkCapabilities.setUids(oldUsers);
+            mNetworkCapabilities =
+                    new NetworkCapabilities.Builder(mNetworkCapabilities).setUids(oldUsers).build();
             mNetworkAgent = oldNetworkAgent;
             mInterface = oldInterface;
             throw e;
@@ -1454,7 +1466,7 @@
     }
 
     /**
-     * Creates a {@link Set} of non-intersecting {@link UidRange} objects including all UIDs
+     * Creates a {@link Set} of non-intersecting {@code Range<Integer>} objects including all UIDs
      * associated with one user, and any restricted profiles attached to that user.
      *
      * <p>If one of {@param allowedApplications} or {@param disallowedApplications} is provided,
@@ -1467,10 +1479,10 @@
      * @param disallowedApplications (optional) List of applications to deny.
      */
     @VisibleForTesting
-    Set<UidRange> createUserAndRestrictedProfilesRanges(@UserIdInt int userId,
+    Set<Range<Integer>> createUserAndRestrictedProfilesRanges(@UserIdInt int userId,
             @Nullable List<String> allowedApplications,
             @Nullable List<String> disallowedApplications) {
-        final Set<UidRange> ranges = new ArraySet<>();
+        final Set<Range<Integer>> ranges = new ArraySet<>();
 
         // Assign the top-level user to the set of ranges
         addUserToRanges(ranges, userId, allowedApplications, disallowedApplications);
@@ -1494,20 +1506,20 @@
     }
 
     /**
-     * Updates a {@link Set} of non-intersecting {@link UidRange} objects to include all UIDs
+     * Updates a {@link Set} of non-intersecting {@code Range<Integer>} objects to include all UIDs
      * associated with one user.
      *
      * <p>If one of {@param allowedApplications} or {@param disallowedApplications} is provided,
      * the UID ranges will match the app allowlist or denylist specified there. Otherwise, all UIDs
      * in the user will be included.
      *
-     * @param ranges {@link Set} of {@link UidRange}s to which to add.
+     * @param ranges {@link Set} of {@code Range<Integer>}s to which to add.
      * @param userId The userId to add to {@param ranges}.
      * @param allowedApplications (optional) allowlist of applications to include.
      * @param disallowedApplications (optional) denylist of applications to exclude.
      */
     @VisibleForTesting
-    void addUserToRanges(@NonNull Set<UidRange> ranges, @UserIdInt int userId,
+    void addUserToRanges(@NonNull Set<Range<Integer>> ranges, @UserIdInt int userId,
             @Nullable List<String> allowedApplications,
             @Nullable List<String> disallowedApplications) {
         if (allowedApplications != null) {
@@ -1517,40 +1529,41 @@
                 if (start == -1) {
                     start = uid;
                 } else if (uid != stop + 1) {
-                    ranges.add(new UidRange(start, stop));
+                    ranges.add(new Range<Integer>(start, stop));
                     start = uid;
                 }
                 stop = uid;
             }
-            if (start != -1) ranges.add(new UidRange(start, stop));
+            if (start != -1) ranges.add(new Range<Integer>(start, stop));
         } else if (disallowedApplications != null) {
             // Add all ranges for user skipping UIDs for disallowedApplications.
-            final UidRange userRange = UidRange.createForUser(UserHandle.of(userId));
-            int start = userRange.start;
+            final Range<Integer> userRange = createUidRangeForUser(userId);
+            int start = userRange.getLower();
             for (int uid : getAppsUids(disallowedApplications, userId)) {
                 if (uid == start) {
                     start++;
                 } else {
-                    ranges.add(new UidRange(start, uid - 1));
+                    ranges.add(new Range<Integer>(start, uid - 1));
                     start = uid + 1;
                 }
             }
-            if (start <= userRange.stop) ranges.add(new UidRange(start, userRange.stop));
+            if (start <= userRange.getUpper()) {
+                ranges.add(new Range<Integer>(start, userRange.getUpper()));
+            }
         } else {
             // Add all UIDs for the user.
-            ranges.add(UidRange.createForUser(UserHandle.of(userId)));
+            ranges.add(createUidRangeForUser(userId));
         }
     }
 
     // Returns the subset of the full list of active UID ranges the VPN applies to (mVpnUsers) that
     // apply to userId.
-    private static List<UidRange> uidRangesForUser(int userId, Set<UidRange> existingRanges) {
-        // UidRange#createForUser returns the entire range of UIDs available to a macro-user.
-        // This is something like 0-99999 ; {@see UserHandle#PER_USER_RANGE}
-        final UidRange userRange = UidRange.createForUser(UserHandle.of(userId));
-        final List<UidRange> ranges = new ArrayList<>();
-        for (UidRange range : existingRanges) {
-            if (userRange.containsRange(range)) {
+    private static List<Range<Integer>> uidRangesForUser(int userId,
+            Set<Range<Integer>> existingRanges) {
+        final Range<Integer> userRange = createUidRangeForUser(userId);
+        final List<Range<Integer>> ranges = new ArrayList<>();
+        for (Range<Integer> range : existingRanges) {
+            if (userRange.contains(range)) {
                 ranges.add(range);
             }
         }
@@ -1567,12 +1580,13 @@
         UserInfo user = mUserManager.getUserInfo(userId);
         if (user.isRestricted() && user.restrictedProfileParentId == mUserId) {
             synchronized(Vpn.this) {
-                final Set<UidRange> existingRanges = mNetworkCapabilities.getUids();
+                final Set<Range<Integer>> existingRanges = mNetworkCapabilities.getUids();
                 if (existingRanges != null) {
                     try {
                         addUserToRanges(existingRanges, userId, mConfig.allowedApplications,
                                 mConfig.disallowedApplications);
-                        mNetworkCapabilities.setUids(existingRanges);
+                        mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities)
+                                .setUids(existingRanges).build();
                     } catch (Exception e) {
                         Log.wtf(TAG, "Failed to add restricted user to owner", e);
                     }
@@ -1595,13 +1609,14 @@
         UserInfo user = mUserManager.getUserInfo(userId);
         if (user.isRestricted() && user.restrictedProfileParentId == mUserId) {
             synchronized(Vpn.this) {
-                final Set<UidRange> existingRanges = mNetworkCapabilities.getUids();
+                final Set<Range<Integer>> existingRanges = mNetworkCapabilities.getUids();
                 if (existingRanges != null) {
                     try {
-                        final List<UidRange> removedRanges =
+                        final List<Range<Integer>> removedRanges =
                                 uidRangesForUser(userId, existingRanges);
                         existingRanges.removeAll(removedRanges);
-                        mNetworkCapabilities.setUids(existingRanges);
+                        mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities)
+                                .setUids(existingRanges).build();
                     } catch (Exception e) {
                         Log.wtf(TAG, "Failed to remove restricted user to owner", e);
                     }
@@ -1659,7 +1674,7 @@
         final Set<UidRangeParcel> rangesToRemove = new ArraySet<>(mBlockedUidsAsToldToConnectivity);
         final Set<UidRangeParcel> rangesToAdd;
         if (enforce) {
-            final Set<UidRange> restrictedProfilesRanges =
+            final Set<Range<Integer>> restrictedProfilesRanges =
                     createUserAndRestrictedProfilesRanges(mUserId,
                     /* allowedApplications */ null,
                     /* disallowedApplications */ exemptedPackages);
@@ -1668,11 +1683,12 @@
             // The UID range of the first user (0-99999) would block the IPSec traffic, which comes
             // directly from the kernel and is marked as uid=0. So we adjust the range to allow
             // it through (b/69873852).
-            for (UidRange range : restrictedProfilesRanges) {
-                if (range.start == 0 && range.stop != 0) {
-                    rangesThatShouldBeBlocked.add(new UidRangeParcel(1, range.stop));
-                } else if (range.start != 0) {
-                    rangesThatShouldBeBlocked.add(new UidRangeParcel(range.start, range.stop));
+            for (Range<Integer> range : restrictedProfilesRanges) {
+                if (range.getLower() == 0 && range.getUpper() != 0) {
+                    rangesThatShouldBeBlocked.add(new UidRangeParcel(1, range.getUpper()));
+                } else if (range.getLower() != 0) {
+                    rangesThatShouldBeBlocked.add(
+                            new UidRangeParcel(range.getLower(), range.getUpper()));
                 }
             }
 
@@ -1694,12 +1710,12 @@
     }
 
     /**
-     * Tell ConnectivityService to add or remove a list of {@link UidRange}s to the list of UIDs
-     * that are only allowed to make connections through sockets that have had {@code protect()}
-     * called on them.
+     * Tell ConnectivityService to add or remove a list of {@link UidRangeParcel}s to the list of
+     * UIDs that are only allowed to make connections through sockets that have had
+     * {@code protect()} called on them.
      *
      * @param enforce {@code true} to add to the denylist, {@code false} to remove.
-     * @param ranges {@link Collection} of {@link UidRange}s to add (if {@param enforce} is
+     * @param ranges {@link Collection} of {@link UidRangeParcel}s to add (if {@param enforce} is
      *               {@code true}) or to remove.
      * @return {@code true} if all of the UIDs were added/removed. {@code false} otherwise,
      *         including added ranges that already existed or removed ones that didn't.
@@ -1881,7 +1897,12 @@
         if (!isRunningLocked()) {
             return false;
         }
-        return mNetworkCapabilities.appliesToUid(uid);
+        final Set<Range<Integer>> uids = mNetworkCapabilities.getUids();
+        if (uids == null) return true;
+        for (final Range<Integer> range : uids) {
+            if (range.contains(uid)) return true;
+        }
+        return false;
     }
 
     /**
@@ -2698,7 +2719,8 @@
 
                     mConfig.routes.clear();
                     for (final RouteInfo route : oldRoutes) {
-                        mConfig.routes.add(new RouteInfo(route.getDestination(), RTN_UNREACHABLE));
+                        mConfig.routes.add(new RouteInfo(route.getDestination(), null /*gateway*/,
+                                null /*iface*/, RTN_UNREACHABLE));
                     }
                     if (mNetworkAgent != null) {
                         mNetworkAgent.sendLinkProperties(makeLinkProperties());
@@ -3037,10 +3059,12 @@
                 // Add a throw route for the VPN server endpoint, if one was specified.
                 if (endpointAddress instanceof Inet4Address) {
                     mConfig.routes.add(new RouteInfo(
-                            new IpPrefix(endpointAddress, 32), RTN_THROW));
+                            new IpPrefix(endpointAddress, 32), null /*gateway*/,
+                            null /*iface*/, RTN_THROW));
                 } else if (endpointAddress instanceof Inet6Address) {
                     mConfig.routes.add(new RouteInfo(
-                            new IpPrefix(endpointAddress, 128), RTN_THROW));
+                            new IpPrefix(endpointAddress, 128), null /*gateway*/,
+                            null /*iface*/, RTN_THROW));
                 } else {
                     Log.e(TAG, "Unknown IP address family for VPN endpoint: "
                             + endpointAddress);
@@ -3340,4 +3364,12 @@
                     firstChildSessionCallback);
         }
     }
+
+    /**
+     * Returns the entire range of UIDs available to a macro-user. This is something like 0-99999.
+     */
+    @VisibleForTesting
+    static Range<Integer> createUidRangeForUser(int userId) {
+        return new Range<Integer>(userId * PER_USER_RANGE, (userId + 1) * PER_USER_RANGE - 1);
+    }
 }
diff --git a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
index fa03e59..47eb3eb 100644
--- a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
+++ b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
@@ -405,7 +405,8 @@
         for (final IkeTrafficSelector selector : trafficSelectors) {
             for (final IpPrefix prefix :
                     new IpRange(selector.startingAddress, selector.endingAddress).asIpPrefixes()) {
-                routes.add(new RouteInfo(prefix, null));
+                routes.add(new RouteInfo(prefix, null /*gateway*/, null /*iface*/,
+                        RouteInfo.RTN_UNICAST));
             }
         }
 
diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java
index 251b579..1261296 100644
--- a/services/core/java/com/android/server/display/BrightnessTracker.java
+++ b/services/core/java/com/android/server/display/BrightnessTracker.java
@@ -652,8 +652,11 @@
                     builder.setPackageName(parser.getAttributeValue(null, ATTR_PACKAGE_NAME));
                     builder.setUserId(mInjector.getUserId(mUserManager,
                             parser.getAttributeInt(null, ATTR_USER)));
-                    builder.setUniqueDisplayId(
-                            parser.getAttributeValue(null, ATTR_UNIQUE_DISPLAY_ID));
+                    String uniqueDisplayId = parser.getAttributeValue(null, ATTR_UNIQUE_DISPLAY_ID);
+                    if (uniqueDisplayId == null) {
+                        uniqueDisplayId = "";
+                    }
+                    builder.setUniqueDisplayId(uniqueDisplayId);
                     builder.setBatteryLevel(parser.getAttributeFloat(null, ATTR_BATTERY_LEVEL));
                     builder.setNightMode(parser.getAttributeBoolean(null, ATTR_NIGHT_MODE));
                     builder.setColorTemperature(
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 92196c8..c010906 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -20,6 +20,7 @@
 import static android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT;
 import static android.Manifest.permission.CAPTURE_VIDEO_OUTPUT;
 import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
+import static android.hardware.display.DisplayManager.EventsMask;
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
@@ -28,6 +29,7 @@
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE;
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED;
+import static android.hardware.display.DisplayManagerGlobal.DisplayEvent;
 import static android.hardware.display.DisplayViewport.VIEWPORT_EXTERNAL;
 import static android.hardware.display.DisplayViewport.VIEWPORT_INTERNAL;
 import static android.hardware.display.DisplayViewport.VIEWPORT_VIRTUAL;
@@ -125,6 +127,7 @@
 import java.util.Arrays;
 import java.util.Optional;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicLong;
 import java.util.function.Consumer;
 
 /**
@@ -820,14 +823,16 @@
     }
 
     private void registerCallbackInternal(IDisplayManagerCallback callback, int callingPid,
-            int callingUid) {
+            int callingUid, @EventsMask long eventsMask) {
         synchronized (mSyncRoot) {
-            if (mCallbacks.get(callingPid) != null) {
-                throw new SecurityException("The calling process has already "
-                        + "registered an IDisplayManagerCallback.");
+            CallbackRecord record = mCallbacks.get(callingPid);
+
+            if (record != null) {
+                record.updateEventsMask(eventsMask);
+                return;
             }
 
-            CallbackRecord record = new CallbackRecord(callingPid, callingUid, callback);
+            record = new CallbackRecord(callingPid, callingUid, callback, eventsMask);
             try {
                 IBinder binder = callback.asBinder();
                 binder.linkToDeath(record, 0);
@@ -1699,7 +1704,7 @@
         }
     }
 
-    private void sendDisplayEventLocked(int displayId, int event) {
+    private void sendDisplayEventLocked(int displayId, @DisplayEvent int event) {
         Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_EVENT, displayId, event);
         mHandler.sendMessage(msg);
     }
@@ -1728,7 +1733,8 @@
 
     // Runs on Handler thread.
     // Delivers display event notifications to callbacks.
-    private void deliverDisplayEvent(int displayId, ArraySet<Integer> uids, int event) {
+    private void deliverDisplayEvent(int displayId, ArraySet<Integer> uids,
+            @DisplayEvent int event) {
         if (DEBUG) {
             Slog.d(TAG, "Delivering display event: displayId="
                     + displayId + ", event=" + event);
@@ -2063,13 +2069,20 @@
         public final int mPid;
         public final int mUid;
         private final IDisplayManagerCallback mCallback;
+        private @EventsMask AtomicLong mEventsMask;
 
         public boolean mWifiDisplayScanRequested;
 
-        CallbackRecord(int pid, int uid, IDisplayManagerCallback callback) {
+        CallbackRecord(int pid, int uid, IDisplayManagerCallback callback,
+                @EventsMask long eventsMask) {
             mPid = pid;
             mUid = uid;
             mCallback = callback;
+            mEventsMask = new AtomicLong(eventsMask);
+        }
+
+        public void updateEventsMask(@EventsMask long eventsMask) {
+            mEventsMask.set(eventsMask);
         }
 
         @Override
@@ -2080,7 +2093,11 @@
             onCallbackDied(this);
         }
 
-        public void notifyDisplayEventAsync(int displayId, int event) {
+        public void notifyDisplayEventAsync(int displayId, @DisplayEvent int event) {
+            if (!shouldSendEvent(event)) {
+                return;
+            }
+
             try {
                 mCallback.onDisplayEvent(displayId, event);
             } catch (RemoteException ex) {
@@ -2089,6 +2106,22 @@
                 binderDied();
             }
         }
+
+        private boolean shouldSendEvent(@DisplayEvent int event) {
+            final long mask = mEventsMask.get();
+            switch (event) {
+                case DisplayManagerGlobal.EVENT_DISPLAY_ADDED:
+                    return (mask & DisplayManager.EVENT_FLAG_DISPLAY_ADDED) != 0;
+                case DisplayManagerGlobal.EVENT_DISPLAY_CHANGED:
+                    return (mask & DisplayManager.EVENT_FLAG_DISPLAY_CHANGED) != 0;
+                case DisplayManagerGlobal.EVENT_DISPLAY_REMOVED:
+                    return (mask & DisplayManager.EVENT_FLAG_DISPLAY_REMOVED) != 0;
+                default:
+                    // This should never happen.
+                    Slog.e(TAG, "Unknown display event " + event);
+                    return true;
+            }
+        }
     }
 
     @VisibleForTesting
@@ -2153,6 +2186,14 @@
 
         @Override // Binder call
         public void registerCallback(IDisplayManagerCallback callback) {
+            registerCallbackWithEventMask(callback, DisplayManager.EVENT_FLAG_DISPLAY_ADDED
+                    | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
+                    | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED);
+        }
+
+        @Override // Binder call
+        public void registerCallbackWithEventMask(IDisplayManagerCallback callback,
+                @EventsMask long eventsMask) {
             if (callback == null) {
                 throw new IllegalArgumentException("listener must not be null");
             }
@@ -2161,7 +2202,7 @@
             final int callingUid = Binder.getCallingUid();
             final long token = Binder.clearCallingIdentity();
             try {
-                registerCallbackInternal(callback, callingPid, callingUid);
+                registerCallbackInternal(callback, callingPid, callingUid, eventsMask);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
diff --git a/services/core/java/com/android/server/display/color/ColorDisplayShellCommand.java b/services/core/java/com/android/server/display/color/ColorDisplayShellCommand.java
index b4555f8..7d9b0aa 100644
--- a/services/core/java/com/android/server/display/color/ColorDisplayShellCommand.java
+++ b/services/core/java/com/android/server/display/color/ColorDisplayShellCommand.java
@@ -28,7 +28,7 @@
             + "      Shows this message.\n"
             + "    set-saturation LEVEL\n"
             + "      Sets the device saturation to the given LEVEL, 0-100 inclusive.\n"
-            + "    set-layer-saturation CALLER_PACKAGE TARGET_PACKAGE LEVEL\n"
+            + "    set-layer-saturation LEVEL CALLER_PACKAGE TARGET_PACKAGE\n"
             + "      Sets the saturation LEVEL for all layers of the TARGET_PACKAGE, attributed\n"
             + "      to the CALLER_PACKAGE. The lowest LEVEL from any CALLER_PACKAGE is applied.\n";
 
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index cbe6e69..0925027 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -2606,6 +2606,11 @@
     }
 
     // Native callback
+    private void notifyDropWindow(IBinder token, float x, float y) {
+        mWindowManagerCallbacks.notifyDropWindow(token, x, y);
+    }
+
+    // Native callback
     private void notifyUntrustedTouch(String packageName) {
         // TODO(b/169067926): Remove toast after gathering feedback on dogfood.
         if (!UNTRUSTED_TOUCHES_TOAST || ArrayUtils.contains(
@@ -3035,6 +3040,11 @@
          * Called when the focused window has changed.
          */
         void notifyFocusChanged(IBinder oldToken, IBinder newToken);
+
+        /**
+         * Called when the drag over window has changed.
+         */
+        void notifyDropWindow(IBinder token, float x, float y);
     }
 
     /**
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java b/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
index 7e5e427..8e84002 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
@@ -54,7 +54,7 @@
         public final boolean mIsSystemLocale;
         public final boolean mIsSystemLanguage;
 
-        public ImeSubtypeListItem(CharSequence imeName, CharSequence subtypeName,
+        ImeSubtypeListItem(CharSequence imeName, CharSequence subtypeName,
                 InputMethodInfo imi, int subtypeId, String subtypeLocale, String systemLocale) {
             mImeName = imeName;
             mSubtypeName = subtypeName;
@@ -71,8 +71,8 @@
                     // TODO: Use Locale#getLanguage or Locale#toLanguageTag
                     final String systemLanguage = parseLanguageFromLocaleString(systemLocale);
                     final String subtypeLanguage = parseLanguageFromLocaleString(subtypeLocale);
-                    mIsSystemLanguage = systemLanguage.length() >= 2 &&
-                            systemLanguage.equals(subtypeLanguage);
+                    mIsSystemLanguage = systemLanguage.length() >= 2
+                            && systemLanguage.equals(subtypeLanguage);
                 }
             }
         }
@@ -158,7 +158,7 @@
                 return true;
             }
             if (o instanceof ImeSubtypeListItem) {
-                final ImeSubtypeListItem that = (ImeSubtypeListItem)o;
+                final ImeSubtypeListItem that = (ImeSubtypeListItem) o;
                 return Objects.equals(this.mImi, that.mImi) && this.mSubtypeId == that.mSubtypeId;
             }
             return false;
@@ -172,7 +172,7 @@
         private final String mSystemLocaleStr;
         private final InputMethodSettings mSettings;
 
-        public InputMethodAndSubtypeList(Context context, InputMethodSettings settings) {
+        InputMethodAndSubtypeList(Context context, InputMethodSettings settings) {
             mContext = context;
             mSettings = settings;
             mPm = context.getPackageManager();
@@ -244,7 +244,7 @@
 
     private static class StaticRotationList {
         private final List<ImeSubtypeListItem> mImeSubtypeList;
-        public StaticRotationList(final List<ImeSubtypeListItem> imeSubtypeList) {
+        StaticRotationList(final List<ImeSubtypeListItem> imeSubtypeList) {
             mImeSubtypeList = imeSubtypeList;
         }
 
@@ -257,8 +257,8 @@
          */
         private int getIndex(InputMethodInfo imi, InputMethodSubtype subtype) {
             final int currentSubtypeId = calculateSubtypeId(imi, subtype);
-            final int N = mImeSubtypeList.size();
-            for (int i = 0; i < N; ++i) {
+            final int numSubtypes = mImeSubtypeList.size();
+            for (int i = 0; i < numSubtypes; ++i) {
                 final ImeSubtypeListItem isli = mImeSubtypeList.get(i);
                 // Skip until the current IME/subtype is found.
                 if (imi.equals(isli.mImi) && isli.mSubtypeId == currentSubtypeId) {
@@ -280,10 +280,10 @@
             if (currentIndex < 0) {
                 return null;
             }
-            final int N = mImeSubtypeList.size();
-            for (int offset = 1; offset < N; ++offset) {
+            final int numSubtypes = mImeSubtypeList.size();
+            for (int offset = 1; offset < numSubtypes; ++offset) {
                 // Start searching the next IME/subtype from the next of the current index.
-                final int candidateIndex = (currentIndex + offset) % N;
+                final int candidateIndex = (currentIndex + offset) % numSubtypes;
                 final ImeSubtypeListItem candidate = mImeSubtypeList.get(candidateIndex);
                 // Skip if searching inside the current IME only, but the candidate is not
                 // the current IME.
@@ -296,8 +296,8 @@
         }
 
         protected void dump(final Printer pw, final String prefix) {
-            final int N = mImeSubtypeList.size();
-            for (int i = 0; i < N; ++i) {
+            final int numSubtypes = mImeSubtypeList.size();
+            for (int i = 0; i < numSubtypes; ++i) {
                 final int rank = i;
                 final ImeSubtypeListItem item = mImeSubtypeList.get(i);
                 pw.println(prefix + "rank=" + rank + " item=" + item);
@@ -313,8 +313,8 @@
         private DynamicRotationList(final List<ImeSubtypeListItem> imeSubtypeListItems) {
             mImeSubtypeList = imeSubtypeListItems;
             mUsageHistoryOfSubtypeListItemIndex = new int[mImeSubtypeList.size()];
-            final int N = mImeSubtypeList.size();
-            for (int i = 0; i < N; i++) {
+            final int numSubtypes = mImeSubtypeList.size();
+            for (int i = 0; i < numSubtypes; i++) {
                 mUsageHistoryOfSubtypeListItemIndex[i] = i;
             }
         }
@@ -328,13 +328,13 @@
          */
         private int getUsageRank(final InputMethodInfo imi, InputMethodSubtype subtype) {
             final int currentSubtypeId = calculateSubtypeId(imi, subtype);
-            final int N = mUsageHistoryOfSubtypeListItemIndex.length;
-            for (int usageRank = 0; usageRank < N; usageRank++) {
+            final int numItems = mUsageHistoryOfSubtypeListItemIndex.length;
+            for (int usageRank = 0; usageRank < numItems; usageRank++) {
                 final int subtypeListItemIndex = mUsageHistoryOfSubtypeListItemIndex[usageRank];
                 final ImeSubtypeListItem subtypeListItem =
                         mImeSubtypeList.get(subtypeListItemIndex);
-                if (subtypeListItem.mImi.equals(imi) &&
-                        subtypeListItem.mSubtypeId == currentSubtypeId) {
+                if (subtypeListItem.mImi.equals(imi)
+                        && subtypeListItem.mSubtypeId == currentSubtypeId) {
                     return usageRank;
                 }
             }
@@ -363,9 +363,9 @@
                 }
                 return null;
             }
-            final int N = mUsageHistoryOfSubtypeListItemIndex.length;
-            for (int i = 1; i < N; i++) {
-                final int subtypeListItemRank = (currentUsageRank + i) % N;
+            final int numItems = mUsageHistoryOfSubtypeListItemIndex.length;
+            for (int i = 1; i < numItems; i++) {
+                final int subtypeListItemRank = (currentUsageRank + i) % numItems;
                 final int subtypeListItemIndex =
                         mUsageHistoryOfSubtypeListItemIndex[subtypeListItemRank];
                 final ImeSubtypeListItem subtypeListItem =
@@ -399,9 +399,10 @@
                 final List<ImeSubtypeListItem> switchingAwareImeSubtypes =
                         filterImeSubtypeList(sortedEnabledItems,
                                 true /* supportsSwitchingToNextInputMethod */);
-                if (currentInstance != null &&
-                        currentInstance.mSwitchingAwareRotationList != null &&
-                        Objects.equals(currentInstance.mSwitchingAwareRotationList.mImeSubtypeList,
+                if (currentInstance != null
+                        && currentInstance.mSwitchingAwareRotationList != null
+                        && Objects.equals(
+                                currentInstance.mSwitchingAwareRotationList.mImeSubtypeList,
                                 switchingAwareImeSubtypes)) {
                     // Can reuse the current instance.
                     switchingAwareRotationList = currentInstance.mSwitchingAwareRotationList;
@@ -415,9 +416,9 @@
             {
                 final List<ImeSubtypeListItem> switchingUnawareImeSubtypes = filterImeSubtypeList(
                         sortedEnabledItems, false /* supportsSwitchingToNextInputMethod */);
-                if (currentInstance != null &&
-                        currentInstance.mSwitchingUnawareRotationList != null &&
-                        Objects.equals(
+                if (currentInstance != null
+                        && currentInstance.mSwitchingUnawareRotationList != null
+                        && Objects.equals(
                                 currentInstance.mSwitchingUnawareRotationList.mImeSubtypeList,
                                 switchingUnawareImeSubtypes)) {
                     // Can reuse the current instance.
@@ -465,11 +466,11 @@
                 final List<ImeSubtypeListItem> items,
                 final boolean supportsSwitchingToNextInputMethod) {
             final ArrayList<ImeSubtypeListItem> result = new ArrayList<>();
-            final int ALL_ITEMS_COUNT = items.size();
-            for (int i = 0; i < ALL_ITEMS_COUNT; i++) {
+            final int numItems = items.size();
+            for (int i = 0; i < numItems; i++) {
                 final ImeSubtypeListItem item = items.get(i);
-                if (item.mImi.supportsSwitchingToNextInputMethod() ==
-                        supportsSwitchingToNextInputMethod) {
+                if (item.mImi.supportsSwitchingToNextInputMethod()
+                        == supportsSwitchingToNextInputMethod) {
                     result.add(item);
                 }
             }
diff --git a/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java b/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java
index 60e8cce..348a03b 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java
@@ -92,6 +92,9 @@
                 break;
             }
         }
+        if (keyToIndexMap.size() < 2) {
+            throw new IllegalStateException("Indexing file is corrupt.");
+        }
         return keyToIndexMap;
     }
 
@@ -106,6 +109,9 @@
 
     private static List<String> searchKeysRangeContainingKey(
             List<String> sortedKeyList, String key, int startIndex, int endIndex) {
+        if (endIndex <= startIndex) {
+            throw new IllegalStateException("Indexing file is corrupt.");
+        }
         if (endIndex - startIndex == 1) {
             return Arrays.asList(sortedKeyList.get(startIndex), sortedKeyList.get(endIndex));
         }
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java b/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
index c8c212b..65987444 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
@@ -25,6 +25,9 @@
 import android.annotation.Nullable;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
+import android.compat.Compatibility;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
 import android.content.Context;
 import android.content.Intent;
 import android.hardware.contexthub.V1_0.ContextHubMsg;
@@ -38,6 +41,7 @@
 import android.hardware.location.NanoAppMessage;
 import android.hardware.location.NanoAppState;
 import android.os.Binder;
+import android.os.Build;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
@@ -113,6 +117,14 @@
      */
     private static final String RECEIVE_MSG_NOTE = "NanoappMessageDelivery ";
 
+    /**
+     * For clients targeting S and above, a SecurityException is thrown when they are in the denied
+     * authorization state and attempt to send a message to a nanoapp.
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
+    private static final long CHANGE_ID_AUTH_STATE_DENIED = 181350407L;
+
     /*
      * The context of the service.
      */
@@ -351,6 +363,8 @@
      *
      * @param message the message to send
      * @return the error code of sending the message
+     * @throws SecurityException if this client doesn't have permissions to send a message to the
+     * nanoapp
      */
     @ContextHubTransaction.Result
     @Override
@@ -362,7 +376,13 @@
             int authState = mMessageChannelNanoappIdMap.getOrDefault(
                     message.getNanoAppId(), AUTHORIZATION_UNKNOWN);
             if (authState == AUTHORIZATION_DENIED) {
-                return ContextHubTransaction.RESULT_FAILED_PERMISSION_DENIED;
+                if (Compatibility.isChangeEnabled(CHANGE_ID_AUTH_STATE_DENIED)) {
+                    throw new SecurityException("Client doesn't have valid permissions to send"
+                            + " message to " + message.getNanoAppId());
+                }
+                // Return a bland error code for apps targeting old SDKs since they wouldn't be able
+                // to use an error code added in S.
+                return ContextHubTransaction.RESULT_FAILED_UNKNOWN;
             } else if (authState == AUTHORIZATION_UNKNOWN) {
                 // Only check permissions the first time a nanoapp is queried since nanoapp
                 // permissions don't currently change at runtime. If the host permission changes
@@ -375,7 +395,7 @@
 
             int contextHubId = mAttachedContextHubInfo.getId();
             try {
-                result = mContextHubProxy.sendMessageToHub(contextHubId, messageToNanoApp);
+                result = mContextHubProxy.getHub().sendMessageToHub(contextHubId, messageToNanoApp);
             } catch (RemoteException e) {
                 Log.e(TAG, "RemoteException in sendMessageToNanoApp (target hub ID = "
                         + contextHubId + ")", e);
diff --git a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
index 3a5c220..3245fdf 100644
--- a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
+++ b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
@@ -104,12 +104,6 @@
             int hubId, IContexthubCallback callback) throws RemoteException;
 
     /**
-     * Calls the appropriate sendMessageToHub function depending on the HAL version.
-     */
-    public abstract int sendMessageToHub(int hubId,
-            android.hardware.contexthub.V1_0.ContextHubMsg message) throws RemoteException;
-
-    /**
      * @return A valid instance of Contexthub HAL 1.0.
      */
     public abstract android.hardware.contexthub.V1_0.IContexthub getHub();
@@ -180,11 +174,6 @@
             mHub.registerCallback(hubId, callback);
         }
 
-        public int sendMessageToHub(int hubId,
-                android.hardware.contexthub.V1_0.ContextHubMsg message) throws RemoteException {
-            return mHub.sendMessageToHub(hubId, message);
-        }
-
         public android.hardware.contexthub.V1_0.IContexthub getHub() {
             return mHub;
         }
@@ -234,11 +223,6 @@
             mHub.registerCallback(hubId, callback);
         }
 
-        public int sendMessageToHub(int hubId,
-                android.hardware.contexthub.V1_0.ContextHubMsg message) throws RemoteException {
-            return mHub.sendMessageToHub(hubId, message);
-        }
-
         public android.hardware.contexthub.V1_0.IContexthub getHub() {
             return mHub;
         }
@@ -304,14 +288,6 @@
             mHub.registerCallback_1_2(hubId, callback);
         }
 
-        public int sendMessageToHub(int hubId,
-                android.hardware.contexthub.V1_0.ContextHubMsg message) throws RemoteException {
-            android.hardware.contexthub.V1_2.ContextHubMsg newMessage =
-                    new android.hardware.contexthub.V1_2.ContextHubMsg();
-            newMessage.msg_1_0 = message;
-            return mHub.sendMessageToHub_1_2(hubId, newMessage);
-        }
-
         public android.hardware.contexthub.V1_0.IContexthub getHub() {
             return mHub;
         }
diff --git a/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java b/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java
index 6d250ec..6201b94 100644
--- a/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java
+++ b/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java
@@ -119,19 +119,11 @@
             for (UserAuthInfo userAuthInfo : pendingResetLockuts) {
                 Slog.d(TAG, "Resetting face lockout for sensor: " + sensorId
                         + ", user: " + userAuthInfo.userId);
-                final VerifyCredentialResponse response = spManager.verifyChallengeInternal(
-                        getGatekeeperService(), userAuthInfo.gatekeeperPassword, challenge,
-                        userAuthInfo.userId);
-                if (response == null) {
-                    Slog.wtf(TAG, "VerifyChallenge failed, null response");
-                    continue;
+                final byte[] hat = requestHatFromGatekeeperPassword(spManager, userAuthInfo,
+                        challenge);
+                if (hat != null) {
+                    faceManager.resetLockout(sensorId, userAuthInfo.userId, hat);
                 }
-                if (response.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
-                    Slog.wtf(TAG, "VerifyChallenge failed, response: "
-                            + response.getResponseCode());
-                }
-                faceManager.resetLockout(sensorId, userAuthInfo.userId,
-                        response.getGatekeeperHAT());
             }
 
             sensorIds.remove(sensorId);
@@ -146,15 +138,6 @@
                 finishCallback.onFinished();
             }
         }
-
-        synchronized IGateKeeperService getGatekeeperService() {
-            final IBinder service = ServiceManager.getService(Context.GATEKEEPER_SERVICE);
-            if (service == null) {
-                Slog.e(TAG, "Unable to acquire GateKeeperService");
-                return null;
-            }
-            return IGateKeeperService.Stub.asInterface(service);
-        }
     }
 
     @Nullable private FaceResetLockoutTask mFaceResetLockoutTask;
@@ -214,10 +197,19 @@
                         mFingerprintManager.resetLockout(prop.sensorId, user.userId,
                                 null /* hardwareAuthToken */);
                     }
+                } else if (!prop.resetLockoutRequiresChallenge) {
+                    for (UserAuthInfo user : pendingResetLockouts) {
+                        Slog.d(TAG, "Resetting fingerprint lockout for sensor: " + prop.sensorId
+                                + ", user: " + user.userId);
+                        final byte[] hat = requestHatFromGatekeeperPassword(mSpManager, user,
+                                0 /* challenge */);
+                        if (hat != null) {
+                            mFingerprintManager.resetLockout(prop.sensorId, user.userId, hat);
+                        }
+                    }
                 } else {
-                    Slog.e(TAG, "Fingerprint resetLockout with HAT not supported yet");
-                    // TODO(b/152414803): Implement this when resetLockout is implemented below
-                    //  the framework.
+                    Slog.w(TAG, "No fingerprint HAL interface requires HAT with challenge"
+                            + ", sensorId: " + prop.sensorId);
                 }
             }
         }
@@ -228,11 +220,6 @@
      * in-flight challenge, we generate a single challenge to reset lockout for all profiles. This
      * hopefully reduces/eliminates issues such as overwritten challenge, incorrectly revoked
      * challenge, or other race conditions.
-     *
-     * TODO(b/162965646) This logic can be avoided if multiple in-flight challenges are supported.
-     *  Though it will need to continue to exist to support existing HIDLs, each profile that
-     *  requires resetLockout could have its own challenge, and the `mPendingResetLockouts` queue
-     *  can be avoided.
      */
     private void processPendingLockoutsForFace(List<UserAuthInfo> pendingResetLockouts) {
         if (mFaceManager != null) {
@@ -251,10 +238,60 @@
             mFaceResetLockoutTask = new FaceResetLockoutTask(mFaceFinishCallback, mFaceManager,
                     mSpManager, sensorIds, pendingResetLockouts);
             for (final FaceSensorPropertiesInternal prop : faceSensorProperties) {
-                // Generate a challenge for each sensor. The challenge does not need to be
-                // per-user, since the HAT returned by gatekeeper contains userId.
-                mFaceManager.generateChallenge(prop.sensorId, mFaceResetLockoutTask);
+                if (prop.resetLockoutRequiresHardwareAuthToken) {
+                    if (prop.resetLockoutRequiresChallenge) {
+                        // Generate a challenge for each sensor. The challenge does not need to be
+                        // per-user, since the HAT returned by gatekeeper contains userId.
+                        mFaceManager.generateChallenge(prop.sensorId, mFaceResetLockoutTask);
+                    } else {
+                        for (UserAuthInfo user : pendingResetLockouts) {
+                            Slog.d(TAG, "Resetting face lockout for sensor: " + prop.sensorId
+                                    + ", user: " + user.userId);
+                            final byte[] hat = requestHatFromGatekeeperPassword(mSpManager, user,
+                                    0 /* challenge */);
+                            if (hat != null) {
+                                mFaceManager.resetLockout(prop.sensorId, user.userId, hat);
+                            }
+                        }
+                    }
+                } else {
+                    Slog.w(TAG, "Lockout is below the HAL for all face authentication interfaces"
+                            + ", sensorId: " + prop.sensorId);
+                }
             }
         }
     }
+
+    @Nullable
+    private static byte[] requestHatFromGatekeeperPassword(
+            @NonNull SyntheticPasswordManager spManager,
+            @NonNull UserAuthInfo userAuthInfo, long challenge) {
+        final VerifyCredentialResponse response = spManager.verifyChallengeInternal(
+                getGatekeeperService(), userAuthInfo.gatekeeperPassword, challenge,
+                userAuthInfo.userId);
+        if (response == null) {
+            Slog.wtf(TAG, "VerifyChallenge failed, null response");
+            return null;
+        }
+        if (response.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
+            Slog.wtf(TAG, "VerifyChallenge failed, response: "
+                    + response.getResponseCode());
+            return null;
+        }
+        if (response.getGatekeeperHAT() == null) {
+            Slog.e(TAG, "Null HAT received from spManager");
+        }
+
+        return response.getGatekeeperHAT();
+    }
+
+    @Nullable
+    private static synchronized IGateKeeperService getGatekeeperService() {
+        final IBinder service = ServiceManager.getService(Context.GATEKEEPER_SERVICE);
+        if (service == null) {
+            Slog.e(TAG, "Unable to acquire GateKeeperService");
+            return null;
+        }
+        return IGateKeeperService.Stub.asInterface(service);
+    }
 }
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 43c7365..22a9a47 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -91,7 +91,6 @@
 import android.security.AndroidKeyStoreMaintenance;
 import android.security.Authorization;
 import android.security.KeyStore;
-import android.security.keystore.AndroidKeyStoreProvider;
 import android.security.keystore.KeyProperties;
 import android.security.keystore.KeyProtection;
 import android.security.keystore.UserNotAuthenticatedException;
@@ -158,7 +157,6 @@
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Objects;
-import java.util.Optional;
 import java.util.Random;
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
@@ -263,13 +261,7 @@
 
         @Override
         public void onStart() {
-            Optional<Boolean> keystore2_enabled =
-                    android.sysprop.Keystore2Properties.keystore2_enabled();
-            if (keystore2_enabled.isPresent() && keystore2_enabled.get()) {
-                android.security.keystore2.AndroidKeyStoreProvider.install();
-            } else {
-                AndroidKeyStoreProvider.install();
-            }
+            android.security.keystore2.AndroidKeyStoreProvider.install();
             mLockSettingsService = new LockSettingsService(getContext());
             publishBinderService("lock_settings", mLockSettingsService);
         }
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index da62aca..350563f 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -58,6 +58,23 @@
 import static android.net.NetworkPolicy.LIMIT_DISABLED;
 import static android.net.NetworkPolicy.SNOOZE_NEVER;
 import static android.net.NetworkPolicy.WARNING_DISABLED;
+import static android.net.NetworkPolicyManager.ALLOWED_METERED_REASON_MASK;
+import static android.net.NetworkPolicyManager.ALLOWED_METERED_REASON_USER_EXEMPTED;
+import static android.net.NetworkPolicyManager.ALLOWED_REASON_FOREGROUND;
+import static android.net.NetworkPolicyManager.ALLOWED_REASON_NONE;
+import static android.net.NetworkPolicyManager.ALLOWED_REASON_POWER_SAVE_ALLOWLIST;
+import static android.net.NetworkPolicyManager.ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST;
+import static android.net.NetworkPolicyManager.ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS;
+import static android.net.NetworkPolicyManager.ALLOWED_REASON_SYSTEM;
+import static android.net.NetworkPolicyManager.BLOCKED_METERED_REASON_ADMIN_DISABLED;
+import static android.net.NetworkPolicyManager.BLOCKED_METERED_REASON_DATA_SAVER;
+import static android.net.NetworkPolicyManager.BLOCKED_METERED_REASON_MASK;
+import static android.net.NetworkPolicyManager.BLOCKED_METERED_REASON_USER_RESTRICTED;
+import static android.net.NetworkPolicyManager.BLOCKED_REASON_APP_STANDBY;
+import static android.net.NetworkPolicyManager.BLOCKED_REASON_BATTERY_SAVER;
+import static android.net.NetworkPolicyManager.BLOCKED_REASON_DOZE;
+import static android.net.NetworkPolicyManager.BLOCKED_REASON_NONE;
+import static android.net.NetworkPolicyManager.BLOCKED_REASON_RESTRICTED_MODE;
 import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
 import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
 import static android.net.NetworkPolicyManager.MASK_ALL_NETWORKS;
@@ -157,7 +174,6 @@
 import android.database.ContentObserver;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
-import android.net.IConnectivityManager;
 import android.net.INetworkManagementEventObserver;
 import android.net.INetworkPolicyListener;
 import android.net.INetworkPolicyManager;
@@ -246,6 +262,7 @@
 import com.android.internal.util.StatLogger;
 import com.android.internal.util.XmlUtils;
 import com.android.net.module.util.NetworkIdentityUtils;
+import com.android.net.module.util.PermissionUtils;
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
 import com.android.server.ServiceThread;
@@ -413,6 +430,14 @@
     private static final int MSG_SET_NETWORK_TEMPLATE_ENABLED = 18;
     private static final int MSG_SUBSCRIPTION_PLANS_CHANGED = 19;
     private static final int MSG_STATS_PROVIDER_LIMIT_REACHED = 20;
+    // TODO: Add similar docs for other messages.
+    /**
+     * Message to indicate that reasons for why an uid is blocked changed.
+     * arg1 = uid
+     * arg2 = oldBlockedReasons
+     * obj = newBlockedReasons
+     */
+    private static final int MSG_BLOCKED_REASON_CHANGED = 21;
 
     private static final int UID_MSG_STATE_CHANGED = 100;
     private static final int UID_MSG_GONE = 101;
@@ -559,7 +584,10 @@
 
     /** Foreground at UID granularity. */
     @GuardedBy("mUidRulesFirstLock")
-    final SparseArray<UidState> mUidState = new SparseArray<UidState>();
+    private final SparseArray<UidState> mUidState = new SparseArray<>();
+
+    @GuardedBy("mUidRulesFirstLock")
+    private final SparseArray<UidBlockedState> mUidBlockedState = new SparseArray<>();
 
     /** Map from network ID to last observed meteredness state */
     @GuardedBy("mNetworkPoliciesSecondLock")
@@ -1188,10 +1216,11 @@
 
     private static boolean updateCapabilityChange(SparseBooleanArray lastValues, boolean newValue,
             Network network) {
-        final boolean lastValue = lastValues.get(network.netId, false);
-        final boolean changed = (lastValue != newValue) || lastValues.indexOfKey(network.netId) < 0;
+        final boolean lastValue = lastValues.get(network.getNetId(), false);
+        final boolean changed = (lastValue != newValue)
+                || lastValues.indexOfKey(network.getNetId()) < 0;
         if (changed) {
-            lastValues.put(network.netId, newValue);
+            lastValues.put(network.getNetId(), newValue);
         }
         return changed;
     }
@@ -1214,7 +1243,7 @@
                         mNetworkRoaming, newRoaming, network);
 
                 if (meteredChanged || roamingChanged) {
-                    mLogger.meterednessChanged(network.netId, newMetered);
+                    mLogger.meterednessChanged(network.getNetId(), newMetered);
                     updateNetworkRulesNL();
                 }
             }
@@ -1980,7 +2009,7 @@
         mNetIdToSubId.clear();
         final ArrayMap<NetworkStateSnapshot, NetworkIdentity> identified = new ArrayMap<>();
         for (final NetworkStateSnapshot snapshot : snapshots) {
-            mNetIdToSubId.put(snapshot.network.netId, parseSubId(snapshot));
+            mNetIdToSubId.put(snapshot.network.getNetId(), parseSubId(snapshot));
 
             // Policies matched by NPMS only match by subscriber ID or by ssid. Thus subtype
             // in the object created here is never used and its value doesn't matter, so use
@@ -2876,15 +2905,18 @@
     }
 
     @Override
-    public void registerListener(INetworkPolicyListener listener) {
+    public void registerListener(@NonNull INetworkPolicyListener listener) {
+        Objects.requireNonNull(listener);
         // TODO: Remove CONNECTIVITY_INTERNAL and the *AnyPermissionOf methods above after all apps
         //  have declared OBSERVE_NETWORK_POLICY.
         enforceAnyPermissionOf(CONNECTIVITY_INTERNAL, OBSERVE_NETWORK_POLICY);
         mListeners.register(listener);
+        // TODO: Send callbacks to the newly registered listener
     }
 
     @Override
-    public void unregisterListener(INetworkPolicyListener listener) {
+    public void unregisterListener(@NonNull INetworkPolicyListener listener) {
+        Objects.requireNonNull(listener);
         // TODO: Remove CONNECTIVITY_INTERNAL and the *AnyPermissionOf methods above after all apps
         //  have declared OBSERVE_NETWORK_POLICY.
         enforceAnyPermissionOf(CONNECTIVITY_INTERNAL, OBSERVE_NETWORK_POLICY);
@@ -3078,8 +3110,16 @@
     @Override
     public int getRestrictBackgroundByCaller() {
         mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG);
-        final int uid = Binder.getCallingUid();
+        return getRestrictBackgroundStatusInternal(Binder.getCallingUid());
+    }
 
+    @Override
+    public int getRestrictBackgroundStatus(int uid) {
+        PermissionUtils.enforceNetworkStackPermission(mContext);
+        return getRestrictBackgroundStatusInternal(uid);
+    }
+
+    private int getRestrictBackgroundStatusInternal(int uid) {
         synchronized (mUidRulesFirstLock) {
             // Must clear identity because getUidPolicy() is restricted to system.
             final long token = Binder.clearCallingIdentity();
@@ -3548,6 +3588,7 @@
      * Get multipath preference value for the given network.
      */
     public int getMultipathPreference(Network network) {
+        PermissionUtils.enforceNetworkStackPermission(mContext);
         final Integer preference = mMultipathPolicyTracker.getMultipathPreference(network);
         if (preference != null) {
             return preference;
@@ -3921,6 +3962,7 @@
                 mUidRules.put(uid, newUidRule);
                 mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRule).sendToTarget();
             }
+            updateBlockedReasonsForRestrictedModeUL(uid);
         });
         if (mRestrictedNetworkingMode) {
             // firewall rules only need to be set when this mode is being enabled.
@@ -3941,6 +3983,7 @@
             mUidRules.put(uid, newUidRule);
             mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRule).sendToTarget();
         }
+        updateBlockedReasonsForRestrictedModeUL(uid);
 
         // if restricted networking mode is on, and the app has an access exemption, the uid rule
         // will not change, but the firewall rule will have to be updated.
@@ -3952,6 +3995,31 @@
         }
     }
 
+    private void updateBlockedReasonsForRestrictedModeUL(int uid) {
+        UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
+        if (uidBlockedState == null) {
+            uidBlockedState = new UidBlockedState();
+            mUidBlockedState.put(uid, uidBlockedState);
+        }
+        final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
+        if (mRestrictedNetworkingMode) {
+            uidBlockedState.blockedReasons |= BLOCKED_REASON_RESTRICTED_MODE;
+        } else {
+            uidBlockedState.blockedReasons &= ~BLOCKED_REASON_RESTRICTED_MODE;
+        }
+        if (hasRestrictedModeAccess(uid)) {
+            uidBlockedState.allowedReasons |= ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS;
+        } else {
+            uidBlockedState.allowedReasons &= ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS;
+        }
+        uidBlockedState.updateEffectiveBlockedReasons();
+        if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) {
+            mHandler.obtainMessage(MSG_BLOCKED_REASON_CHANGED, uid,
+                    uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons)
+                    .sendToTarget();
+        }
+    }
+
     private int getNewRestrictedModeUidRule(int uid, int oldUidRule) {
         int newRule = oldUidRule;
         newRule &= ~MASK_RESTRICTED_MODE_NETWORKS;
@@ -4072,11 +4140,21 @@
         boolean isWhitelisted = mPowerSaveTempWhitelistAppIds.get(appId)
                 || mPowerSaveWhitelistAppIds.get(appId);
         if (!deviceIdleMode) {
-            isWhitelisted = isWhitelisted || mPowerSaveWhitelistExceptIdleAppIds.get(appId);
+            isWhitelisted = isWhitelisted || isWhitelistedFromPowerSaveExceptIdleUL(uid);
         }
         return isWhitelisted;
     }
 
+    /**
+     * Returns whether a uid is allowlisted from power saving restrictions, except Device idle
+     * (eg: Battery Saver and app idle).
+     */
+    @GuardedBy("mUidRulesFirstLock")
+    private boolean isWhitelistedFromPowerSaveExceptIdleUL(int uid) {
+        final int appId = UserHandle.getAppId(uid);
+        return mPowerSaveWhitelistExceptIdleAppIds.get(appId);
+    }
+
     // NOTE: since both fw_dozable and fw_powersave uses the same map
     // (mPowerSaveTempWhitelistAppIds) for allowlisting, we can reuse their logic in this method.
     @GuardedBy("mUidRulesFirstLock")
@@ -4521,6 +4599,11 @@
         final int oldUidRules = mUidRules.get(uid, RULE_NONE);
         final boolean isForeground = isUidForegroundOnRestrictBackgroundUL(uid);
         final boolean isRestrictedByAdmin = isRestrictedByAdminUL(uid);
+        UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
+        if (uidBlockedState == null) {
+            uidBlockedState = new UidBlockedState();
+            mUidBlockedState.put(uid, uidBlockedState);
+        }
 
         final boolean isDenied = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;
         final boolean isAllowed = (uidPolicy & POLICY_ALLOW_METERED_BACKGROUND) != 0;
@@ -4545,6 +4628,16 @@
             }
         }
 
+        int newBlockedReasons = BLOCKED_REASON_NONE;
+        int newAllowedReasons = ALLOWED_REASON_NONE;
+        newBlockedReasons |= (isRestrictedByAdmin ? BLOCKED_METERED_REASON_ADMIN_DISABLED : 0);
+        newBlockedReasons |= (mRestrictBackground ? BLOCKED_METERED_REASON_DATA_SAVER : 0);
+        newBlockedReasons |= (isDenied ? BLOCKED_METERED_REASON_USER_RESTRICTED : 0);
+
+        newAllowedReasons |= (isSystem(uid) ? ALLOWED_REASON_SYSTEM : 0);
+        newAllowedReasons |= (isForeground ? ALLOWED_REASON_FOREGROUND : 0);
+        newAllowedReasons |= (isAllowed ? ALLOWED_METERED_REASON_USER_EXEMPTED : 0);
+
         if (LOGV) {
             Log.v(TAG, "updateRuleForRestrictBackgroundUL(" + uid + ")"
                     + ": isForeground=" +isForeground
@@ -4616,6 +4709,18 @@
 
             // Dispatch changed rule to existing listeners.
             mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRules).sendToTarget();
+
+            final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
+            uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons
+                    & ~BLOCKED_METERED_REASON_MASK) | newBlockedReasons;
+            uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons
+                    & ~ALLOWED_METERED_REASON_MASK) | newAllowedReasons;
+            uidBlockedState.updateEffectiveBlockedReasons();
+            if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) {
+                mHandler.obtainMessage(MSG_BLOCKED_REASON_CHANGED, uid,
+                        uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons)
+                        .sendToTarget();
+            }
         }
     }
 
@@ -4690,6 +4795,12 @@
         // Copy existing uid rules and clear ALL_NETWORK rules.
         int newUidRules = oldUidRules & (~MASK_ALL_NETWORKS);
 
+        UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
+        if (uidBlockedState == null) {
+            uidBlockedState = new UidBlockedState();
+            mUidBlockedState.put(uid, uidBlockedState);
+        }
+
         // First step: define the new rule based on user restrictions and foreground state.
 
         // NOTE: if statements below could be inlined, but it's easier to understand the logic
@@ -4702,6 +4813,20 @@
             newUidRules |= isWhitelisted ? RULE_ALLOW_ALL : RULE_REJECT_ALL;
         }
 
+        int newBlockedReasons = BLOCKED_REASON_NONE;
+        int newAllowedReasons = ALLOWED_REASON_NONE;
+        newBlockedReasons |= (mRestrictPower ? BLOCKED_REASON_BATTERY_SAVER : 0);
+        newBlockedReasons |= (mDeviceIdleMode ? BLOCKED_REASON_DOZE : 0);
+        newBlockedReasons |= (isUidIdle ? BLOCKED_REASON_APP_STANDBY : 0);
+        newBlockedReasons |= (uidBlockedState.blockedReasons & BLOCKED_REASON_RESTRICTED_MODE);
+
+        newAllowedReasons |= (isSystem(uid) ? ALLOWED_REASON_SYSTEM : 0);
+        newAllowedReasons |= (isForeground ? ALLOWED_REASON_FOREGROUND : 0);
+        newAllowedReasons |= (isWhitelistedFromPowerSaveUL(uid, true)
+                ? ALLOWED_REASON_POWER_SAVE_ALLOWLIST : 0);
+        newAllowedReasons |= (isWhitelistedFromPowerSaveExceptIdleUL(uid)
+                ? ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST : 0);
+
         if (LOGV) {
             Log.v(TAG, "updateRulesForPowerRestrictionsUL(" + uid + ")"
                     + ", isIdle: " + isUidIdle
@@ -4733,6 +4858,18 @@
             mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRules).sendToTarget();
         }
 
+        final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
+        uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons
+                & BLOCKED_METERED_REASON_MASK) | newBlockedReasons;
+        uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons
+                & ALLOWED_METERED_REASON_MASK) | newAllowedReasons;
+        uidBlockedState.updateEffectiveBlockedReasons();
+        if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) {
+            mHandler.obtainMessage(MSG_BLOCKED_REASON_CHANGED, uid,
+                    uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons)
+                    .sendToTarget();
+        }
+
         return newUidRules;
     }
 
@@ -4762,61 +4899,57 @@
     }
 
     private void dispatchUidRulesChanged(INetworkPolicyListener listener, int uid, int uidRules) {
-        if (listener != null) {
-            try {
-                listener.onUidRulesChanged(uid, uidRules);
-            } catch (RemoteException ignored) {
-            }
+        try {
+            listener.onUidRulesChanged(uid, uidRules);
+        } catch (RemoteException ignored) {
         }
     }
 
     private void dispatchMeteredIfacesChanged(INetworkPolicyListener listener,
             String[] meteredIfaces) {
-        if (listener != null) {
-            try {
-                listener.onMeteredIfacesChanged(meteredIfaces);
-            } catch (RemoteException ignored) {
-            }
+        try {
+            listener.onMeteredIfacesChanged(meteredIfaces);
+        } catch (RemoteException ignored) {
         }
     }
 
     private void dispatchRestrictBackgroundChanged(INetworkPolicyListener listener,
             boolean restrictBackground) {
-        if (listener != null) {
-            try {
-                listener.onRestrictBackgroundChanged(restrictBackground);
-            } catch (RemoteException ignored) {
-            }
+        try {
+            listener.onRestrictBackgroundChanged(restrictBackground);
+        } catch (RemoteException ignored) {
         }
     }
 
     private void dispatchUidPoliciesChanged(INetworkPolicyListener listener, int uid,
             int uidPolicies) {
-        if (listener != null) {
-            try {
-                listener.onUidPoliciesChanged(uid, uidPolicies);
-            } catch (RemoteException ignored) {
-            }
+        try {
+            listener.onUidPoliciesChanged(uid, uidPolicies);
+        } catch (RemoteException ignored) {
         }
     }
 
     private void dispatchSubscriptionOverride(INetworkPolicyListener listener, int subId,
             int overrideMask, int overrideValue, int[] networkTypes) {
-        if (listener != null) {
-            try {
-                listener.onSubscriptionOverride(subId, overrideMask, overrideValue, networkTypes);
-            } catch (RemoteException ignored) {
-            }
+        try {
+            listener.onSubscriptionOverride(subId, overrideMask, overrideValue, networkTypes);
+        } catch (RemoteException ignored) {
         }
     }
 
     private void dispatchSubscriptionPlansChanged(INetworkPolicyListener listener, int subId,
             SubscriptionPlan[] plans) {
-        if (listener != null) {
-            try {
-                listener.onSubscriptionPlansChanged(subId, plans);
-            } catch (RemoteException ignored) {
-            }
+        try {
+            listener.onSubscriptionPlansChanged(subId, plans);
+        } catch (RemoteException ignored) {
+        }
+    }
+
+    private void dispatchBlockedReasonChanged(INetworkPolicyListener listener, int uid,
+            int oldBlockedReasons, int newBlockedReasons) {
+        try {
+            listener.onBlockedReasonChanged(uid, oldBlockedReasons, newBlockedReasons);
+        } catch (RemoteException ignored) {
         }
     }
 
@@ -4973,6 +5106,19 @@
                     mListeners.finishBroadcast();
                     return true;
                 }
+                case MSG_BLOCKED_REASON_CHANGED: {
+                    final int uid = msg.arg1;
+                    final int newBlockedReasons = msg.arg2;
+                    final int oldBlockedReasons = (int) msg.obj;
+                    final int length = mListeners.beginBroadcast();
+                    for (int i = 0; i < length; i++) {
+                        final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
+                        dispatchBlockedReasonChanged(listener, uid,
+                                oldBlockedReasons, newBlockedReasons);
+                    }
+                    mListeners.finishBroadcast();
+                    return true;
+                }
                 default: {
                     return false;
                 }
@@ -5632,7 +5778,7 @@
 
     @GuardedBy("mNetworkPoliciesSecondLock")
     private int getSubIdLocked(Network network) {
-        return mNetIdToSubId.get(network.netId, INVALID_SUBSCRIPTION_ID);
+        return mNetIdToSubId.get(network.getNetId(), INVALID_SUBSCRIPTION_ID);
     }
 
     @GuardedBy("mNetworkPoliciesSecondLock")
@@ -5704,6 +5850,51 @@
         return (bundle != null) ? bundle.getBoolean(key, defaultValue) : defaultValue;
     }
 
+    private class UidBlockedState {
+        public int blockedReasons;
+        public int allowedReasons;
+        public int effectiveBlockedReasons;
+
+        UidBlockedState() {
+            blockedReasons = BLOCKED_REASON_NONE;
+            allowedReasons = ALLOWED_REASON_NONE;
+            effectiveBlockedReasons = BLOCKED_REASON_NONE;
+        }
+
+        void updateEffectiveBlockedReasons() {
+            effectiveBlockedReasons = blockedReasons;
+            // If the uid is not subject to any blocked reasons, then return early
+            if (blockedReasons == BLOCKED_REASON_NONE) {
+                return;
+            }
+            if ((allowedReasons & ALLOWED_REASON_SYSTEM) != 0) {
+                effectiveBlockedReasons = BLOCKED_REASON_NONE;
+            }
+            if ((allowedReasons & ALLOWED_REASON_FOREGROUND) != 0) {
+                effectiveBlockedReasons &= ~BLOCKED_REASON_BATTERY_SAVER;
+                effectiveBlockedReasons &= ~BLOCKED_REASON_DOZE;
+                effectiveBlockedReasons &= ~BLOCKED_REASON_APP_STANDBY;
+                effectiveBlockedReasons &= ~BLOCKED_METERED_REASON_DATA_SAVER;
+                effectiveBlockedReasons &= ~BLOCKED_METERED_REASON_USER_RESTRICTED;
+            }
+            if ((allowedReasons & ALLOWED_REASON_POWER_SAVE_ALLOWLIST) != 0) {
+                effectiveBlockedReasons &= ~BLOCKED_REASON_BATTERY_SAVER;
+                effectiveBlockedReasons &= ~BLOCKED_REASON_DOZE;
+                effectiveBlockedReasons &= ~BLOCKED_REASON_APP_STANDBY;
+            }
+            if ((allowedReasons & ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST) != 0) {
+                effectiveBlockedReasons &= ~BLOCKED_REASON_BATTERY_SAVER;
+                effectiveBlockedReasons &= ~BLOCKED_REASON_APP_STANDBY;
+            }
+            if ((allowedReasons & ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS) != 0) {
+                effectiveBlockedReasons &= ~BLOCKED_REASON_RESTRICTED_MODE;
+            }
+            if ((allowedReasons & ALLOWED_METERED_REASON_USER_EXEMPTED) != 0) {
+                effectiveBlockedReasons &= ~BLOCKED_METERED_REASON_DATA_SAVER;
+            }
+        }
+    }
+
     private class NotificationId {
         private final String mTag;
         private final int mId;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index e588366..eb4f9d3 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -3576,15 +3576,30 @@
                     pkg, uid, channelId, conversationId, true, includeDeleted);
         }
 
+        // Returns 'true' if the given channel has a notification associated
+        // with an active foreground service.
+        private void enforceDeletingChannelHasNoFgService(String pkg, int userId,
+                String channelId) {
+            if (mAmi.hasForegroundServiceNotification(pkg, userId, channelId)) {
+                Slog.w(TAG, "Package u" + userId + "/" + pkg
+                        + " may not delete notification channel '"
+                        + channelId + "' with fg service");
+                throw new SecurityException("Not allowed to delete channel " + channelId
+                        + " with a foreground service");
+            }
+        }
+
         @Override
         public void deleteNotificationChannel(String pkg, String channelId) {
             checkCallerIsSystemOrSameApp(pkg);
             final int callingUid = Binder.getCallingUid();
+            final int callingUser = UserHandle.getUserId(callingUid);
             if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
                 throw new IllegalArgumentException("Cannot delete default channel");
             }
+            enforceDeletingChannelHasNoFgService(pkg, callingUser, channelId);
             cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
-                    UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
+                    callingUser, REASON_CHANNEL_BANNED, null);
             mPreferencesHelper.deleteNotificationChannel(pkg, callingUid, channelId);
             mListeners.notifyNotificationChannelChanged(pkg,
                     UserHandle.getUserHandleForUid(callingUid),
@@ -3597,19 +3612,23 @@
         public void deleteConversationNotificationChannels(String pkg, int uid,
                 String conversationId) {
             checkCallerIsSystem();
-            final int callingUid = Binder.getCallingUid();
             List<NotificationChannel> channels =
                     mPreferencesHelper.getNotificationChannelsByConversationId(
                             pkg, uid, conversationId);
             if (!channels.isEmpty()) {
+                // Preflight for fg service notifications in these channels:  do nothing
+                // unless they're all eligible
+                final int appUserId = UserHandle.getUserId(uid);
                 for (NotificationChannel nc : channels) {
+                    final String channelId = nc.getId();
+                    mAmi.stopForegroundServicesForChannel(pkg, appUserId, channelId);
                     cancelAllNotificationsInt(MY_UID, MY_PID, pkg, nc.getId(), 0, 0, true,
-                            UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
-                    mPreferencesHelper.deleteNotificationChannel(pkg, callingUid, nc.getId());
+                            appUserId, REASON_CHANNEL_BANNED, null);
+                    mPreferencesHelper.deleteNotificationChannel(pkg, uid, channelId);
                     mListeners.notifyNotificationChannelChanged(pkg,
-                            UserHandle.getUserHandleForUid(callingUid),
+                            UserHandle.getUserHandleForUid(uid),
                             mPreferencesHelper.getNotificationChannel(
-                                    pkg, callingUid, nc.getId(), true),
+                                    pkg, uid, channelId, true),
                             NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
                 }
                 handleSavePolicyFile();
@@ -3640,13 +3659,20 @@
             NotificationChannelGroup groupToDelete =
                     mPreferencesHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
             if (groupToDelete != null) {
+                // Preflight for allowability
+                final int userId = UserHandle.getUserId(callingUid);
+                List<NotificationChannel> groupChannels = groupToDelete.getChannels();
+                for (int i = 0; i < groupChannels.size(); i++) {
+                    enforceDeletingChannelHasNoFgService(pkg, userId,
+                            groupChannels.get(i).getId());
+                }
                 List<NotificationChannel> deletedChannels =
                         mPreferencesHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
                 for (int i = 0; i < deletedChannels.size(); i++) {
                     final NotificationChannel deletedChannel = deletedChannels.get(i);
                     cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
                             true,
-                            UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
+                            userId, REASON_CHANNEL_BANNED,
                             null);
                     mListeners.notifyNotificationChannelChanged(pkg,
                             UserHandle.getUserHandleForUid(callingUid),
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index dbd1211..27b1648 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -103,7 +103,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.Optional;
 import java.util.Set;
 
 /**
@@ -312,7 +311,7 @@
                     // Initialize any users that can't be switched to, as their state would
                     // never be setup in onSwitchUser(). We will switch to the system user right
                     // after this, and its state will be setup there.
-                    updatePackageManager(mImpl.updateOverlaysForUser(users.get(i).id));
+                    updatePackageManagerLocked(mImpl.updateOverlaysForUser(users.get(i).id));
                 }
             }
         }
@@ -329,9 +328,8 @@
             // ensure overlays in the settings are up-to-date, and propagate
             // any asset changes to the rest of the system
             synchronized (mLock) {
-                updateActivityManager(updatePackageManager(mImpl.updateOverlaysForUser(newUserId)));
+                updateTargetPackagesLocked(mImpl.updateOverlaysForUser(newUserId));
             }
-            persistSettings();
         } finally {
             traceEnd(TRACE_TAG_RRO);
         }
@@ -415,7 +413,8 @@
                                 packageName, userId);
                         if (pkg != null && !mPackageManager.isInstantApp(packageName, userId)) {
                             try {
-                                updateTargetPackages(mImpl.onPackageAdded(packageName, userId));
+                                updateTargetPackagesLocked(
+                                        mImpl.onPackageAdded(packageName, userId));
                             } catch (OperationFailedException e) {
                                 Slog.e(TAG, "onPackageAdded internal error", e);
                             }
@@ -437,7 +436,8 @@
                                 packageName, userId);
                         if (pkg != null && !mPackageManager.isInstantApp(packageName, userId)) {
                             try {
-                                updateTargetPackages(mImpl.onPackageChanged(packageName, userId));
+                                updateTargetPackagesLocked(
+                                        mImpl.onPackageChanged(packageName, userId));
                             } catch (OperationFailedException e) {
                                 Slog.e(TAG, "onPackageChanged internal error", e);
                             }
@@ -459,7 +459,8 @@
                                 packageName, userId);
                         if (pkg != null && !mPackageManager.isInstantApp(packageName, userId)) {
                             try {
-                                updateTargetPackages(mImpl.onPackageReplacing(packageName, userId));
+                                updateTargetPackagesLocked(
+                                        mImpl.onPackageReplacing(packageName, userId));
                             } catch (OperationFailedException e) {
                                 Slog.e(TAG, "onPackageReplacing internal error", e);
                             }
@@ -481,7 +482,8 @@
                                 packageName, userId);
                         if (pkg != null && !mPackageManager.isInstantApp(packageName, userId)) {
                             try {
-                                updateTargetPackages(mImpl.onPackageReplaced(packageName, userId));
+                                updateTargetPackagesLocked(
+                                        mImpl.onPackageReplaced(packageName, userId));
                             } catch (OperationFailedException e) {
                                 Slog.e(TAG, "onPackageReplaced internal error", e);
                             }
@@ -500,7 +502,7 @@
                 for (int userId : userIds) {
                     synchronized (mLock) {
                         mPackageManager.onPackageRemoved(packageName, userId);
-                        updateTargetPackages(mImpl.onPackageRemoved(packageName, userId));
+                        updateTargetPackagesLocked(mImpl.onPackageRemoved(packageName, userId));
                     }
                 }
             } finally {
@@ -519,7 +521,7 @@
                         try {
                             traceBegin(TRACE_TAG_RRO, "OMS ACTION_USER_ADDED");
                             synchronized (mLock) {
-                                updatePackageManager(mImpl.updateOverlaysForUser(userId));
+                                updatePackageManagerLocked(mImpl.updateOverlaysForUser(userId));
                             }
                         } finally {
                             traceEnd(TRACE_TAG_RRO);
@@ -624,7 +626,8 @@
                 try {
                     synchronized (mLock) {
                         try {
-                            updateTargetPackages(mImpl.setEnabled(overlay, enable, realUserId));
+                            updateTargetPackagesLocked(
+                                    mImpl.setEnabled(overlay, enable, realUserId));
                             return true;
                         } catch (OperationFailedException e) {
                             return false;
@@ -656,9 +659,10 @@
                 try {
                     synchronized (mLock) {
                         try {
-                            mImpl.setEnabledExclusive(overlay,
-                                    false /* withinCategory */, realUserId)
-                                .ifPresent(OverlayManagerService.this::updateTargetPackages);
+                            mImpl.setEnabledExclusive(
+                                    overlay, false /* withinCategory */, realUserId)
+                                    .ifPresent(
+                                            OverlayManagerService.this::updateTargetPackagesLocked);
                             return true;
                         } catch (OperationFailedException e) {
                             return false;
@@ -693,7 +697,7 @@
                         try {
                             mImpl.setEnabledExclusive(overlay,
                                     true /* withinCategory */, realUserId)
-                                .ifPresent(OverlayManagerService.this::updateTargetPackages);
+                                .ifPresent(OverlayManagerService.this::updateTargetPackagesLocked);
                             return true;
                         } catch (OperationFailedException e) {
                             return false;
@@ -728,7 +732,7 @@
                     synchronized (mLock) {
                         try {
                             mImpl.setPriority(overlay, parentOverlay, realUserId)
-                                .ifPresent(OverlayManagerService.this::updateTargetPackages);
+                                .ifPresent(OverlayManagerService.this::updateTargetPackagesLocked);
                             return true;
                         } catch (OperationFailedException e) {
                             return false;
@@ -759,7 +763,8 @@
                 try {
                     synchronized (mLock) {
                         try {
-                            updateTargetPackages(mImpl.setHighestPriority(overlay, realUserId));
+                            updateTargetPackagesLocked(
+                                    mImpl.setHighestPriority(overlay, realUserId));
                             return true;
                         } catch (OperationFailedException e) {
                             return false;
@@ -791,7 +796,7 @@
                     synchronized (mLock) {
                         try {
                             mImpl.setLowestPriority(overlay, realUserId)
-                                .ifPresent(OverlayManagerService.this::updateTargetPackages);
+                                .ifPresent(OverlayManagerService.this::updateTargetPackagesLocked);
                             return true;
                         } catch (OperationFailedException e) {
                             return false;
@@ -945,27 +950,12 @@
                 throw new IllegalArgumentException("null transaction");
             }
 
-            // map: userId -> set<package-name>: target packages of overlays in
-            // this transaction
-            final SparseArray<Set<String>> transactionTargets = new SparseArray<>();
-
-            // map: userId -> set<package-name>: packages that need to reload
-            // their resources due to changes to the overlays in this
-            // transaction
-            final SparseArray<List<String>> affectedPackagesToUpdate = new SparseArray<>();
-
             synchronized (mLock) {
                 // execute the requests (as calling user)
+                Set<PackageAndUser> affectedPackagesToUpdate = null;
                 for (final OverlayManagerTransaction.Request request : transaction) {
-                    executeRequest(request).forEach(
-                            target -> {
-                                Set<String> userTargets = transactionTargets.get(target.userId);
-                                if (userTargets == null) {
-                                    userTargets = new ArraySet<>();
-                                    transactionTargets.put(target.userId, userTargets);
-                                }
-                                userTargets.add(target.packageName);
-                            });
+                    affectedPackagesToUpdate = CollectionUtils.addAll(affectedPackagesToUpdate,
+                            executeRequest(request));
                 }
 
                 // past the point of no return: the entire transaction has been
@@ -973,37 +963,11 @@
                 // system_server
                 final long ident = Binder.clearCallingIdentity();
                 try {
-                    persistSettings();
-
-                    // inform the package manager about the new paths
-                    for (int index = 0; index < transactionTargets.size(); index++) {
-                        final int userId = transactionTargets.keyAt(index);
-                        final List<String> affectedTargets =
-                                updatePackageManager(transactionTargets.valueAt(index), userId);
-                        affectedPackagesToUpdate.put(userId, affectedTargets);
-                    }
+                    updateTargetPackagesLocked(affectedPackagesToUpdate);
                 } finally {
                     Binder.restoreCallingIdentity(ident);
                 }
-            } // synchronized (mLock)
-
-            FgThread.getHandler().post(() -> {
-                final long ident = Binder.clearCallingIdentity();
-                try {
-                    // schedule apps to refresh
-                    updateActivityManager(affectedPackagesToUpdate);
-
-                    // broadcast the ACTION_OVERLAY_CHANGED intents
-                    for (int index = 0; index < transactionTargets.size(); index++) {
-                        final int userId = transactionTargets.keyAt(index);
-                        for (String pkg: transactionTargets.valueAt(index)) {
-                            broadcastActionOverlayChanged(pkg, userId);
-                        }
-                    }
-                } finally {
-                    Binder.restoreCallingIdentity(ident);
-                }
-            });
+            }
         }
 
         @Override
@@ -1382,32 +1346,37 @@
         }
     }
 
-    private void updateTargetPackages(@Nullable PackageAndUser updatedTarget) {
+    private void updateTargetPackagesLocked(@Nullable PackageAndUser updatedTarget) {
         if (updatedTarget != null) {
-            updateTargetPackages(Set.of(updatedTarget));
+            updateTargetPackagesLocked(Set.of(updatedTarget));
         }
     }
 
-    private void updateTargetPackages(@Nullable Set<PackageAndUser> updatedTargets) {
+    private void updateTargetPackagesLocked(@Nullable Set<PackageAndUser> updatedTargets) {
         if (CollectionUtils.isEmpty(updatedTargets)) {
             return;
         }
-        persistSettings();
+        persistSettingsLocked();
         final SparseArray<ArraySet<String>> userTargets = groupTargetsByUserId(updatedTargets);
-        FgThread.getHandler().post(() -> {
-            for (int i = 0, n = userTargets.size(); i < n; i++) {
-                final ArraySet<String> targets = userTargets.valueAt(i);
-                final int userId = userTargets.keyAt(i);
+        for (int i = 0, n = userTargets.size(); i < n; i++) {
+            final ArraySet<String> targets = userTargets.valueAt(i);
+            final int userId = userTargets.keyAt(i);
+            final List<String> affectedPackages = updatePackageManagerLocked(targets, userId);
+            if (affectedPackages.isEmpty()) {
+                // The package manager paths are already up-to-date.
+                continue;
+            }
 
-                // Update the overlay paths in package manager.
-                final List<String> affectedPackages = updatePackageManager(targets, userId);
+            FgThread.getHandler().post(() -> {
+                // Send configuration changed events for all target packages that have been affected
+                // by overlay state changes.
                 updateActivityManager(affectedPackages, userId);
 
-                // Overlays targeting shared libraries may cause more packages to need to be
-                // refreshed.
+                // Do not send broadcasts for all affected targets. Overlays targeting the framework
+                // or shared libraries may cause too many broadcasts to be sent at once.
                 broadcastActionOverlayChanged(targets, userId);
-            }
-        });
+            });
+        }
     }
 
     @Nullable
@@ -1430,20 +1399,17 @@
 
     private static void broadcastActionOverlayChanged(@NonNull final Set<String> targetPackages,
             final int userId) {
-        CollectionUtils.forEach(targetPackages,
-                target -> broadcastActionOverlayChanged(target, userId));
-    }
-
-    private static void broadcastActionOverlayChanged(String targetPackage, final int userId) {
-        final Intent intent = new Intent(ACTION_OVERLAY_CHANGED,
-                Uri.fromParts("package", targetPackage, null));
-        intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-        try {
-            ActivityManager.getService().broadcastIntent(null, intent, null, null, 0, null, null,
-                    null, android.app.AppOpsManager.OP_NONE, null, false, false, userId);
-        } catch (RemoteException e) {
-            // Intentionally left empty.
-        }
+        CollectionUtils.forEach(targetPackages, target -> {
+            final Intent intent = new Intent(ACTION_OVERLAY_CHANGED,
+                    Uri.fromParts("package", target, null));
+            intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+            try {
+                ActivityManager.getService().broadcastIntent(null, intent, null, null, 0, null,
+                        null, null, android.app.AppOpsManager.OP_NONE, null, false, false, userId);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "broadcastActionOverlayChanged remote exception", e);
+            }
+        });
     }
 
     /**
@@ -1455,18 +1421,13 @@
         try {
             am.scheduleApplicationInfoChanged(targetPackageNames, userId);
         } catch (RemoteException e) {
-            // Intentionally left empty.
-        }
-    }
-
-    private void updateActivityManager(@NonNull SparseArray<List<String>> targetPackageNames) {
-        for (int i = 0, n = targetPackageNames.size(); i < n; i++) {
-            updateActivityManager(targetPackageNames.valueAt(i), targetPackageNames.keyAt(i));
+            Slog.e(TAG, "updateActivityManager remote exception", e);
         }
     }
 
     @NonNull
-    private SparseArray<List<String>> updatePackageManager(@Nullable Set<PackageAndUser> targets) {
+    private SparseArray<List<String>> updatePackageManagerLocked(
+            @Nullable Set<PackageAndUser> targets) {
         if (CollectionUtils.isEmpty(targets)) {
             return new SparseArray<>();
         }
@@ -1474,7 +1435,7 @@
         final SparseArray<ArraySet<String>> userTargets = groupTargetsByUserId(targets);
         for (int i = 0, n = userTargets.size(); i < n; i++) {
             final int userId = userTargets.keyAt(i);
-            affectedTargets.put(userId, updatePackageManager(userTargets.valueAt(i), userId));
+            affectedTargets.put(userId, updatePackageManagerLocked(userTargets.valueAt(i), userId));
         }
         return affectedTargets;
     }
@@ -1485,10 +1446,10 @@
      *         targetPackageNames: the target themselves and shared libraries)
      */
     @NonNull
-    private List<String> updatePackageManager(@NonNull Collection<String> targetPackageNames,
+    private List<String> updatePackageManagerLocked(@NonNull Collection<String> targetPackageNames,
             final int userId) {
         try {
-            traceBegin(TRACE_TAG_RRO, "OMS#updatePackageManager " + targetPackageNames);
+            traceBegin(TRACE_TAG_RRO, "OMS#updatePackageManagerLocked " + targetPackageNames);
             if (DEBUG) {
                 Slog.d(TAG, "Update package manager about changed overlays");
             }
@@ -1535,20 +1496,18 @@
         }
     }
 
-    private void persistSettings() {
+    private void persistSettingsLocked() {
         if (DEBUG) {
             Slog.d(TAG, "Writing overlay settings");
         }
-        synchronized (mLock) {
-            FileOutputStream stream = null;
-            try {
-                stream = mSettingsFile.startWrite();
-                mSettings.persist(stream);
-                mSettingsFile.finishWrite(stream);
-            } catch (IOException | XmlPullParserException e) {
-                mSettingsFile.failWrite(stream);
-                Slog.e(TAG, "failed to persist overlay state", e);
-            }
+        FileOutputStream stream = null;
+        try {
+            stream = mSettingsFile.startWrite();
+            mSettings.persist(stream);
+            mSettingsFile.finishWrite(stream);
+        } catch (IOException | XmlPullParserException e) {
+            mSettingsFile.failWrite(stream);
+            Slog.e(TAG, "failed to persist overlay state", e);
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java b/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java
index aae6ce4..791a105 100644
--- a/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java
+++ b/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java
@@ -19,7 +19,7 @@
 import android.annotation.NonNull;
 import android.content.IntentFilter;
 
-import com.android.server.WatchableIntentResolver;
+import com.android.server.WatchedIntentResolver;
 import com.android.server.utils.Snappable;
 
 import java.util.List;
@@ -28,7 +28,7 @@
  * Used to find a list of {@link CrossProfileIntentFilter}s that match an intent.
  */
 class CrossProfileIntentResolver
-        extends WatchableIntentResolver<CrossProfileIntentFilter, CrossProfileIntentFilter>
+        extends WatchedIntentResolver<CrossProfileIntentFilter, CrossProfileIntentFilter>
         implements Snappable {
     @Override
     protected CrossProfileIntentFilter[] newArray(int size) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 1530e41..ff042c2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -252,6 +252,7 @@
 import android.content.pm.parsing.component.ParsedProcess;
 import android.content.pm.parsing.component.ParsedProvider;
 import android.content.pm.parsing.component.ParsedService;
+import android.content.pm.parsing.component.ParsedUsesPermission;
 import android.content.pm.parsing.result.ParseResult;
 import android.content.pm.parsing.result.ParseTypeImpl;
 import android.content.res.Resources;
@@ -882,7 +883,7 @@
     // Lock for global state used when modifying package state or settings.
     // Methods that must be called with this lock held have
     // the suffix "Locked". Some methods may use the legacy suffix "LP"
-    final Object mLock;
+    final PackageManagerTracedLock mLock;
 
     // Keys are String (package name), values are Package.
     @Watched
@@ -1041,7 +1042,7 @@
 
         private final PackageAbiHelper mAbiHelper;
         private final Context mContext;
-        private final Object mLock;
+        private final PackageManagerTracedLock mLock;
         private final Installer mInstaller;
         private final Object mInstallLock;
         private final Handler mBackgroundHandler;
@@ -1081,7 +1082,7 @@
                 mDomainVerificationManagerInternalProducer;
         private final Singleton<Handler> mHandlerProducer;
 
-        Injector(Context context, Object lock, Installer installer,
+        Injector(Context context, PackageManagerTracedLock lock, Installer installer,
                 Object installLock, PackageAbiHelper abiHelper,
                 Handler backgroundHandler,
                 List<ScanPartition> systemPartitions,
@@ -1181,7 +1182,7 @@
             return mUserManagerProducer.get(this, mPackageManager);
         }
 
-        public Object getLock() {
+        public PackageManagerTracedLock getLock() {
             return mLock;
         }
 
@@ -5963,7 +5964,7 @@
         final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
                 Trace.TRACE_TAG_PACKAGE_MANAGER);
         t.traceBegin("create package manager");
-        final Object lock = new Object();
+        final PackageManagerTracedLock lock = new PackageManagerTracedLock();
         final Object installLock = new Object();
         HandlerThread backgroundThread = new HandlerThread("PackageManagerBg");
         backgroundThread.start();
@@ -26889,11 +26890,12 @@
                     outUpdatedPackageNames.add(targetPackageName);
                     modified = true;
                 }
+
+                if (modified) {
+                    invalidatePackageInfoCache();
+                }
             }
 
-            if (modified) {
-                invalidatePackageInfoCache();
-            }
             return true;
         }
 
@@ -27322,6 +27324,28 @@
             return PackageManagerService.this.getPackageStartability(
                     packageName, callingUid, userId) == PACKAGE_STARTABILITY_FROZEN;
         }
+
+        @Override
+        public boolean isPackageUsesPermissionNeverForLocation(@NonNull String packageName,
+                @NonNull String permissionName) {
+            Objects.requireNonNull(packageName);
+            Objects.requireNonNull(permissionName);
+            final AndroidPackage pkg;
+            synchronized (mLock) {
+                pkg = mPackages.get(packageName);
+            }
+            if (pkg == null) return false;
+            final List<ParsedUsesPermission> usesPermissions = pkg.getUsesPermissions();
+            final int size = usesPermissions.size();
+            for (int i = 0; i < size; i++) {
+                final ParsedUsesPermission usesPermission = usesPermissions.get(i);
+                if (Objects.equals(usesPermission.name, permissionName)) {
+                    return (usesPermission.usesPermissionFlags
+                            & ParsedUsesPermission.FLAG_NEVER_FOR_LOCATION) != 0;
+                }
+            }
+            return false;
+        }
     }
 
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl b/services/core/java/com/android/server/pm/PackageManagerTracedLock.java
similarity index 67%
copy from packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl
copy to services/core/java/com/android/server/pm/PackageManagerTracedLock.java
index 54242be..e15e8a8 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl
+++ b/services/core/java/com/android/server/pm/PackageManagerTracedLock.java
@@ -14,12 +14,11 @@
  * limitations under the License.
  */
 
-package com.android.systemui.shared.recents;
+package com.android.server.pm;
 
 /**
- * Listener interface that Launcher attaches to SystemUI to get split-screen callbacks.
+ * This is a unique class that is used as the PackageManager lock.  It can be targeted for lock
+ * injection, similar to {@link ActivityManagerGlobalLock}.
  */
-oneway interface ISplitScreenListener {
-    void onStagePositionChanged(int stage, int position);
-    void onTaskStageChanged(int taskId, int stage, boolean visible);
+public class PackageManagerTracedLock {
 }
diff --git a/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java b/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java
index c1bfcac..2b11a42 100644
--- a/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java
+++ b/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java
@@ -19,11 +19,11 @@
 import android.annotation.NonNull;
 import android.content.IntentFilter;
 
-import com.android.server.WatchableIntentResolver;
+import com.android.server.WatchedIntentResolver;
 import com.android.server.utils.Snappable;
 
 public class PersistentPreferredIntentResolver
-        extends WatchableIntentResolver<PersistentPreferredActivity, PersistentPreferredActivity>
+        extends WatchedIntentResolver<PersistentPreferredActivity, PersistentPreferredActivity>
         implements Snappable {
     @Override
     protected PersistentPreferredActivity[] newArray(int size) {
diff --git a/services/core/java/com/android/server/pm/PreferredIntentResolver.java b/services/core/java/com/android/server/pm/PreferredIntentResolver.java
index 0e3b85c..10a6b3f 100644
--- a/services/core/java/com/android/server/pm/PreferredIntentResolver.java
+++ b/services/core/java/com/android/server/pm/PreferredIntentResolver.java
@@ -19,14 +19,14 @@
 import android.annotation.NonNull;
 import android.content.IntentFilter;
 
-import com.android.server.WatchableIntentResolver;
+import com.android.server.WatchedIntentResolver;
 import com.android.server.utils.Snappable;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
 
 public class PreferredIntentResolver
-        extends WatchableIntentResolver<PreferredActivity, PreferredActivity>
+        extends WatchedIntentResolver<PreferredActivity, PreferredActivity>
         implements Snappable {
     @Override
     protected PreferredActivity[] newArray(int size) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index ec7b451..b51b833 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -353,7 +353,7 @@
     private static final String ATTR_DATABASE_VERSION = "databaseVersion";
     private static final String ATTR_VALUE = "value";
 
-    private final Object mLock;
+    private final PackageManagerTracedLock mLock;
 
     private final RuntimePermissionPersistence mRuntimePermissionsPersistence;
 
@@ -525,7 +525,7 @@
 
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
     public Settings(Map<String, PackageSetting> pkgSettings) {
-        mLock = new Object();
+        mLock = new PackageManagerTracedLock();
         mPackages.putAll(pkgSettings);
         mAppIds = new WatchedArrayList<>();
         mOtherAppIds = new WatchedSparseArray<>();
@@ -562,7 +562,7 @@
     Settings(File dataDir, RuntimePermissionsPersistence runtimePermissionsPersistence,
             LegacyPermissionDataProvider permissionDataProvider,
             @NonNull DomainVerificationManagerInternal domainVerificationManager,
-            @NonNull Object lock)  {
+            @NonNull PackageManagerTracedLock lock)  {
         mLock = lock;
         mAppIds = new WatchedArrayList<>();
         mOtherAppIds = new WatchedSparseArray<>();
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 0a74032..8f87b19 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -214,7 +214,7 @@
             newSigningDetails = ApkSignatureVerifier.verify(apexPath, minSignatureScheme);
         } catch (PackageParserException e) {
             throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
-                    "Failed to parse APEX package " + apexPath, e);
+                    "Failed to parse APEX package " + apexPath + " : " + e, e);
         }
 
         // Get signing details of the existing package
@@ -232,7 +232,8 @@
                 existingApexPkg.applicationInfo.sourceDir, SignatureSchemeVersion.JAR);
         } catch (PackageParserException e) {
             throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
-                    "Failed to parse APEX package " + existingApexPkg.applicationInfo.sourceDir, e);
+                    "Failed to parse APEX package " + existingApexPkg.applicationInfo.sourceDir
+                            + " : " + e, e);
         }
 
         // Verify signing details for upgrade
@@ -291,7 +292,7 @@
                 }
             } catch (PackageParserException e) {
                 throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
-                        "Failed to parse APEX package " + apexInfo.modulePath, e);
+                        "Failed to parse APEX package " + apexInfo.modulePath + " : " + e, e);
             }
             final PackageInfo activePackage = mApexManager.getPackageInfo(packageInfo.packageName,
                     ApexManager.MATCH_ACTIVE_PACKAGE);
diff --git a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
index 0c8e36b..c8dc1b1 100644
--- a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
+++ b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
@@ -146,47 +146,11 @@
                 uid,
                 compilationReason,
                 compilerFilter,
-                ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_DEX_CODE_BYTES,
-                getDexBytes(path),
-                dexMetadataType);
-        logger.write(
-                sessionId,
-                uid,
-                compilationReason,
-                compilerFilter,
                 ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_TOTAL_TIME,
                 compileTime,
                 dexMetadataType);
     }
 
-    private static long getDexBytes(String apkPath) {
-        StrictJarFile jarFile = null;
-        long dexBytes = 0;
-        try {
-            jarFile = new StrictJarFile(apkPath,
-                    /*verify=*/ false,
-                    /*signatureSchemeRollbackProtectionsEnforced=*/ false);
-            Iterator<ZipEntry> it = jarFile.iterator();
-            while (it.hasNext()) {
-                ZipEntry entry = it.next();
-                if (entry.getName().matches("classes(\\d)*[.]dex")) {
-                    dexBytes += entry.getSize();
-                }
-            }
-            return dexBytes;
-        } catch (IOException ignore) {
-            Slog.e(TAG, "Error when parsing APK " + apkPath);
-            return -1L;
-        } finally {
-            try {
-                if (jarFile != null) {
-                    jarFile.close();
-                }
-            } catch (IOException ignore) {
-            }
-        }
-    }
-
     private static int getDexMetadataType(String dexMetadataPath) {
         if (dexMetadataPath == null) {
             return ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_NONE;
diff --git a/services/core/java/com/android/server/policy/LegacyGlobalActions.java b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
index 9c3a394..5b48abb 100644
--- a/services/core/java/com/android/server/policy/LegacyGlobalActions.java
+++ b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
@@ -24,11 +24,11 @@
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.database.ContentObserver;
 import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
-import android.net.ConnectivityManager;
 import android.os.Build;
 import android.os.Handler;
 import android.os.Message;
@@ -113,7 +113,7 @@
     private boolean mDeviceProvisioned = false;
     private ToggleAction.State mAirplaneState = ToggleAction.State.Off;
     private boolean mIsWaitingForEcmExit = false;
-    private boolean mHasTelephony;
+    private final boolean mHasTelephony;
     private boolean mHasVibrator;
     private final boolean mShowSilentToggle;
     private final EmergencyAffordanceManager mEmergencyAffordanceManager;
@@ -137,9 +137,8 @@
         filter.addAction(TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
         context.registerReceiver(mBroadcastReceiver, filter);
 
-        ConnectivityManager cm = (ConnectivityManager)
-                context.getSystemService(Context.CONNECTIVITY_SERVICE);
-        mHasTelephony = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+        mHasTelephony =
+                context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
 
         // get notified of phone state changes
         TelephonyManager telephonyManager =
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
index fd2d8e1..beebb31 100644
--- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
@@ -16,6 +16,8 @@
 
 package com.android.server.recoverysystem;
 
+import static android.os.UserHandle.USER_SYSTEM;
+
 import android.annotation.IntDef;
 import android.content.Context;
 import android.content.IntentSender;
@@ -33,12 +35,14 @@
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
 import android.os.SystemProperties;
+import android.provider.DeviceConfig;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.widget.LockSettingsInternal;
 import com.android.internal.widget.RebootEscrowListener;
 import com.android.server.LocalServices;
@@ -52,6 +56,8 @@
 import java.io.FileWriter;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * The recovery system service is responsible for coordinating recovery related
@@ -127,10 +133,28 @@
     /**
      * The action to perform upon resume on reboot clear request for a given client.
      */
-    @IntDef({ROR_NOT_REQUESTED,
+    @IntDef({ ROR_NOT_REQUESTED,
             ROR_REQUESTED_NEED_CLEAR,
             ROR_REQUESTED_SKIP_CLEAR})
-    private @interface ResumeOnRebootActionsOnClear{}
+    private @interface ResumeOnRebootActionsOnClear {}
+
+    /**
+     * The error code for reboots initiated by resume on reboot clients.
+     */
+    private static final int REBOOT_ERROR_NONE = 0;
+    private static final int REBOOT_ERROR_UNKNOWN = 1;
+    private static final int REBOOT_ERROR_INVALID_PACKAGE_NAME = 2;
+    private static final int REBOOT_ERROR_LSKF_NOT_CAPTURED = 3;
+    private static final int REBOOT_ERROR_SLOT_MISMATCH = 4;
+    private static final int REBOOT_ERROR_ARM_REBOOT_ESCROW_FAILURE = 5;
+
+    @IntDef({ REBOOT_ERROR_NONE,
+            REBOOT_ERROR_UNKNOWN,
+            REBOOT_ERROR_INVALID_PACKAGE_NAME,
+            REBOOT_ERROR_LSKF_NOT_CAPTURED,
+            REBOOT_ERROR_SLOT_MISMATCH,
+            REBOOT_ERROR_ARM_REBOOT_ESCROW_FAILURE})
+    private @interface ResumeOnRebootRebootErrorCode {}
 
     static class Injector {
         protected final Context mContext;
@@ -202,6 +226,35 @@
         public void threadSleep(long millis) throws InterruptedException {
             Thread.sleep(millis);
         }
+
+        public int getUidFromPackageName(String packageName) {
+            try {
+                return mContext.getPackageManager().getPackageUidAsUser(packageName, USER_SYSTEM);
+            } catch (PackageManager.NameNotFoundException e) {
+                Slog.w(TAG, "Failed to find uid for " + packageName);
+            }
+            return -1;
+        }
+
+        public void reportRebootEscrowPreparationMetrics(int uid,
+                @ResumeOnRebootActionsOnRequest int requestResult, int requestedClientCount) {
+            FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_PREPARATION_REPORTED, uid,
+                    requestResult, requestedClientCount);
+        }
+
+        public void reportRebootEscrowLskfCapturedMetrics(int uid, int requestedClientCount,
+                int requestedToLskfCapturedDurationInSeconds) {
+            FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_LSKF_CAPTURE_REPORTED, uid,
+                    requestedClientCount, requestedToLskfCapturedDurationInSeconds);
+        }
+
+        public void reportRebootEscrowRebootMetrics(int errorCode, int uid,
+                int preparedClientCount, int requestCount, boolean slotSwitch, boolean serverBased,
+                int lskfCapturedToRebootDurationInSeconds, int lskfCapturedCounts) {
+            FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_REBOOT_REPORTED, errorCode,
+                    uid, preparedClientCount, requestCount, slotSwitch, serverBased,
+                    lskfCapturedToRebootDurationInSeconds, lskfCapturedCounts);
+        }
     }
 
     /**
@@ -367,6 +420,16 @@
         }
     }
 
+    private void reportMetricsOnRequestLskf(String packageName, int requestResult) {
+        int uid = mInjector.getUidFromPackageName(packageName);
+        int pendingRequestCount;
+        synchronized (this) {
+            pendingRequestCount = mCallerPendingRequest.size();
+        }
+
+        mInjector.reportRebootEscrowPreparationMetrics(uid, requestResult, pendingRequestCount);
+    }
+
     @Override // Binder call
     public boolean requestLskf(String packageName, IntentSender intentSender) {
         enforcePermissionForResumeOnReboot();
@@ -378,6 +441,8 @@
 
         @ResumeOnRebootActionsOnRequest int action = updateRoRPreparationStateOnNewRequest(
                 packageName, intentSender);
+        reportMetricsOnRequestLskf(packageName, action);
+
         switch (action) {
             case ROR_SKIP_PREPARATION_AND_NOTIFY:
                 // We consider the preparation done if someone else has prepared.
@@ -420,12 +485,26 @@
         return needPreparation ? ROR_NEED_PREPARATION : ROR_SKIP_PREPARATION_NOT_NOTIFY;
     }
 
+    private void reportMetricsOnPreparedForReboot() {
+        List<String> preparedClients;
+        synchronized (this) {
+            preparedClients = new ArrayList<>(mCallerPreparedForReboot);
+        }
+
+        for (String packageName : preparedClients) {
+            int uid = mInjector.getUidFromPackageName(packageName);
+            mInjector.reportRebootEscrowLskfCapturedMetrics(uid, preparedClients.size(),
+                    -1 /* duration */);
+        }
+    }
+
     @Override
     public void onPreparedForReboot(boolean ready) {
         if (!ready) {
             return;
         }
         updateRoRPreparationStateOnPreparedForReboot();
+        reportMetricsOnPreparedForReboot();
     }
 
     private synchronized void updateRoRPreparationStateOnPreparedForReboot() {
@@ -548,22 +627,49 @@
         return true;
     }
 
-    private boolean rebootWithLskfImpl(String packageName, String reason, boolean slotSwitch) {
+    private @ResumeOnRebootRebootErrorCode int armRebootEscrow(String packageName,
+            boolean slotSwitch) {
         if (packageName == null) {
             Slog.w(TAG, "Missing packageName when rebooting with lskf.");
-            return false;
+            return REBOOT_ERROR_INVALID_PACKAGE_NAME;
         }
         if (!isLskfCaptured(packageName)) {
-            return false;
+            return REBOOT_ERROR_LSKF_NOT_CAPTURED;
         }
 
         if (!verifySlotForNextBoot(slotSwitch)) {
-            return false;
+            return REBOOT_ERROR_SLOT_MISMATCH;
         }
 
-        // TODO(xunchang) write the vbmeta digest along with the escrowKey before reboot.
         if (!mInjector.getLockSettingsService().armRebootEscrow()) {
             Slog.w(TAG, "Failure to escrow key for reboot");
+            return REBOOT_ERROR_ARM_REBOOT_ESCROW_FAILURE;
+        }
+
+        return REBOOT_ERROR_NONE;
+    }
+
+    private void reportMetricsOnRebootWithLskf(String packageName, boolean slotSwitch,
+            @ResumeOnRebootRebootErrorCode int errorCode) {
+        int uid = mInjector.getUidFromPackageName(packageName);
+        boolean serverBased = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_OTA,
+                "server_based_ror_enabled", false);
+        int preparedClientCount;
+        synchronized (this) {
+            preparedClientCount = mCallerPreparedForReboot.size();
+        }
+
+        // TODO(b/179105110) report the true value of duration and counts
+        mInjector.reportRebootEscrowRebootMetrics(errorCode, uid, preparedClientCount,
+                1 /* request count */, slotSwitch, serverBased,
+                -1 /* duration */, 1 /* lskf capture count */);
+    }
+
+    private boolean rebootWithLskfImpl(String packageName, String reason, boolean slotSwitch) {
+        @ResumeOnRebootRebootErrorCode int errorCode = armRebootEscrow(packageName, slotSwitch);
+        reportMetricsOnRebootWithLskf(packageName, slotSwitch, errorCode);
+
+        if (errorCode != REBOOT_ERROR_NONE) {
             return false;
         }
 
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 8023fd4..a7b9e95 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -25,7 +25,16 @@
 import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkCapabilities.TRANSPORT_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.METERED_ALL;
+import static android.net.NetworkStats.ROAMING_ALL;
+import static android.net.NetworkTemplate.MATCH_ETHERNET;
+import static android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD;
+import static android.net.NetworkTemplate.MATCH_WIFI_WILDCARD;
 import static android.net.NetworkTemplate.NETWORK_TYPE_ALL;
+import static android.net.NetworkTemplate.OEM_MANAGED_ALL;
 import static android.net.NetworkTemplate.buildTemplateMobileWildcard;
 import static android.net.NetworkTemplate.buildTemplateMobileWithRatType;
 import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
@@ -435,6 +444,7 @@
                     case FrameworkStatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG:
                     case FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED:
                     case FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER:
+                    case FrameworkStatsLog.OEM_MANAGED_BYTES_TRANSFER:
                         synchronized (mDataBytesTransferLock) {
                             return pullDataBytesTransferLocked(atomTag, data);
                         }
@@ -867,6 +877,8 @@
                 FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED));
         mNetworkStatsBaselines.addAll(
                 collectNetworkStatsSnapshotForAtom(FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER));
+        mNetworkStatsBaselines.addAll(
+                collectNetworkStatsSnapshotForAtom(FrameworkStatsLog.OEM_MANAGED_BYTES_TRANSFER));
 
         // Listen to subscription changes to record historical subscriptions that activated before
         // pulling, this is used by {@code DATA_USAGE_BYTES_TRANSFER}.
@@ -879,6 +891,7 @@
         registerMobileBytesTransferBackground();
         registerBytesTransferByTagAndMetered();
         registerDataUsageBytesTransfer();
+        registerOemManagedBytesTransfer();
     }
 
     /**
@@ -1057,7 +1070,7 @@
                             new int[] {TRANSPORT_WIFI, TRANSPORT_CELLULAR},
                             /*slicedByFgbg=*/false, /*slicedByTag=*/true,
                             /*slicedByMetered=*/true, TelephonyManager.NETWORK_TYPE_UNKNOWN,
-                            /*subInfo=*/null));
+                            /*subInfo=*/null, OEM_MANAGED_ALL));
                 }
                 break;
             }
@@ -1067,6 +1080,10 @@
                 }
                 break;
             }
+            case FrameworkStatsLog.OEM_MANAGED_BYTES_TRANSFER: {
+                ret.addAll(getDataUsageBytesTransferSnapshotForOemManaged());
+                break;
+            }
             default:
                 throw new IllegalArgumentException("Unknown atomTag " + atomTag);
         }
@@ -1094,7 +1111,7 @@
             final NetworkStatsExt diff = new NetworkStatsExt(
                     item.stats.subtract(baseline.stats).removeEmptyEntries(), item.transports,
                     item.slicedByFgbg, item.slicedByTag, item.slicedByMetered, item.ratType,
-                    item.subInfo);
+                    item.subInfo, item.oemManaged);
 
             // If no diff, skip.
             if (diff.stats.size() == 0) continue;
@@ -1106,6 +1123,9 @@
                 case FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER:
                     addDataUsageBytesTransferAtoms(diff, pulledData);
                     break;
+                case FrameworkStatsLog.OEM_MANAGED_BYTES_TRANSFER:
+                    addOemDataUsageBytesTransferAtoms(diff, pulledData);
+                    break;
                 default:
                     addNetworkStats(atomTag, pulledData, diff);
             }
@@ -1177,6 +1197,49 @@
         }
     }
 
+    private void addOemDataUsageBytesTransferAtoms(@NonNull NetworkStatsExt statsExt,
+            @NonNull List<StatsEvent> pulledData) {
+        final NetworkStats.Entry entry = new NetworkStats.Entry(); // for recycling
+        final int oemManaged = statsExt.oemManaged;
+        for (final int transport : statsExt.transports) {
+            for (int i = 0; i < statsExt.stats.size(); i++) {
+                statsExt.stats.getValues(i, entry);
+                pulledData.add(FrameworkStatsLog.buildStatsEvent(
+                        FrameworkStatsLog.OEM_MANAGED_BYTES_TRANSFER, entry.uid, (entry.set > 0),
+                        oemManaged, transport, entry.rxBytes, entry.rxPackets, entry.txBytes,
+                        entry.txPackets));
+            }
+        }
+    }
+
+    @NonNull private List<NetworkStatsExt> getDataUsageBytesTransferSnapshotForOemManaged() {
+        final int[] transports = new int[] {MATCH_ETHERNET, MATCH_MOBILE_WILDCARD,
+                MATCH_WIFI_WILDCARD};
+        final int[] oemManagedTypes = new int[] {OEM_PAID | OEM_PRIVATE, OEM_PAID, OEM_PRIVATE};
+
+        final List<NetworkStatsExt> ret = new ArrayList<>();
+
+        for (final int transport : transports) {
+            for (final int oemManaged : oemManagedTypes) {
+                /* A null subscriberId will set wildcard=true, since we aren't trying to select a
+                   specific ssid or subscriber. */
+                final NetworkTemplate template = new NetworkTemplate(transport,
+                        /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null,
+                        METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
+                        oemManaged);
+                final NetworkStats stats = getUidNetworkStatsSnapshotForTemplate(template, true);
+                if (stats != null) {
+                    ret.add(new NetworkStatsExt(sliceNetworkStatsByUidTagAndMetered(stats),
+                            new int[] {transport}, /*slicedByFgbg=*/true, /*slicedByTag=*/true,
+                            /*slicedByMetered=*/true, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+                            /*subInfo=*/null, oemManaged));
+                }
+            }
+        }
+
+        return ret;
+    }
+
     /**
      * Create a snapshot of NetworkStats for a given transport.
      */
@@ -1229,7 +1292,8 @@
             if (stats != null) {
                 ret.add(new NetworkStatsExt(sliceNetworkStatsByFgbg(stats),
                         new int[] {TRANSPORT_CELLULAR}, /*slicedByFgbg=*/true,
-                        /*slicedByTag=*/false, /*slicedByMetered=*/false, ratType, subInfo));
+                        /*slicedByTag=*/false, /*slicedByMetered=*/false, ratType, subInfo,
+                        OEM_MANAGED_ALL));
             }
         }
         return ret;
@@ -1374,6 +1438,19 @@
         );
     }
 
+    private void registerOemManagedBytesTransfer() {
+        int tagId = FrameworkStatsLog.OEM_MANAGED_BYTES_TRANSFER;
+        PullAtomMetadata metadata = new PullAtomMetadata.Builder()
+                .setAdditiveFields(new int[] {5, 6, 7, 8})
+                .build();
+        mStatsManager.setPullAtomCallback(
+                tagId,
+                metadata,
+                BackgroundThread.getExecutor(),
+                mStatsCallbackImpl
+        );
+    }
+
     private void registerBluetoothBytesTransfer() {
         int tagId = FrameworkStatsLog.BLUETOOTH_BYTES_TRANSFER;
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
diff --git a/services/core/java/com/android/server/stats/pull/netstats/NetworkStatsExt.java b/services/core/java/com/android/server/stats/pull/netstats/NetworkStatsExt.java
index 06c81ee..7dbba0d 100644
--- a/services/core/java/com/android/server/stats/pull/netstats/NetworkStatsExt.java
+++ b/services/core/java/com/android/server/stats/pull/netstats/NetworkStatsExt.java
@@ -16,6 +16,8 @@
 
 package com.android.server.stats.pull.netstats;
 
+import static android.net.NetworkTemplate.OEM_MANAGED_ALL;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.net.NetworkStats;
@@ -37,17 +39,18 @@
     public final boolean slicedByTag;
     public final boolean slicedByMetered;
     public final int ratType;
+    public final int oemManaged;
     @Nullable
     public final SubInfo subInfo;
 
     public NetworkStatsExt(@NonNull NetworkStats stats, int[] transports, boolean slicedByFgbg) {
         this(stats, transports, slicedByFgbg, /*slicedByTag=*/false, /*slicedByMetered=*/false,
-                TelephonyManager.NETWORK_TYPE_UNKNOWN, /*subInfo=*/null);
+                TelephonyManager.NETWORK_TYPE_UNKNOWN, /*subInfo=*/null, OEM_MANAGED_ALL);
     }
 
     public NetworkStatsExt(@NonNull NetworkStats stats, int[] transports, boolean slicedByFgbg,
             boolean slicedByTag, boolean slicedByMetered, int ratType,
-            @Nullable SubInfo subInfo) {
+            @Nullable SubInfo subInfo, int oemManaged) {
         this.stats = stats;
 
         // Sort transports array so that we can test for equality without considering order.
@@ -59,6 +62,7 @@
         this.slicedByMetered = slicedByMetered;
         this.ratType = ratType;
         this.subInfo = subInfo;
+        this.oemManaged = oemManaged;
     }
 
     /**
@@ -67,6 +71,7 @@
     public boolean hasSameSlicing(@NonNull NetworkStatsExt other) {
         return Arrays.equals(transports, other.transports) && slicedByFgbg == other.slicedByFgbg
                 && slicedByTag == other.slicedByTag && slicedByMetered == other.slicedByMetered
-                && ratType == other.ratType && Objects.equals(subInfo, other.subInfo);
+                && ratType == other.ratType && Objects.equals(subInfo, other.subInfo)
+                && oemManaged == other.oemManaged;
     }
 }
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 302a23f..c4f5575 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -36,6 +36,7 @@
 import android.hardware.biometrics.PromptInfo;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManager.DisplayListener;
+import android.hardware.fingerprint.IUdfpsHbmListener;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
@@ -828,12 +829,24 @@
     }
 
     @Override
+    public void setUdfpsHbmListener(IUdfpsHbmListener listener) {
+        enforceStatusBarService();
+        if (mBar != null) {
+            try {
+                mBar.setUdfpsHbmListener(listener);
+            } catch (RemoteException ex) {
+            }
+        }
+    }
+
+    @Override
     public void startTracing() {
         if (mBar != null) {
             try {
                 mBar.startTracing();
                 mTracingEnabled = true;
-            } catch (RemoteException ex) {}
+            } catch (RemoteException ex) {
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/timedetector/ConfigurationInternal.java b/services/core/java/com/android/server/timedetector/ConfigurationInternal.java
new file mode 100644
index 0000000..f00f856
--- /dev/null
+++ b/services/core/java/com/android/server/timedetector/ConfigurationInternal.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.timedetector;
+
+import static android.app.time.Capabilities.CAPABILITY_NOT_ALLOWED;
+import static android.app.time.Capabilities.CAPABILITY_POSSESSED;
+
+import android.annotation.UserIdInt;
+import android.app.time.Capabilities.CapabilityState;
+import android.app.time.TimeCapabilities;
+import android.app.time.TimeCapabilitiesAndConfig;
+import android.app.time.TimeConfiguration;
+import android.os.UserHandle;
+
+import java.util.Objects;
+
+/**
+ * Holds configuration values that affect time behaviour.
+ */
+public final class ConfigurationInternal {
+
+    private final @UserIdInt int mUserId;
+    private final boolean mUserConfigAllowed;
+    private final boolean mAutoDetectionEnabled;
+
+    private ConfigurationInternal(Builder builder) {
+        mUserId = builder.mUserId;
+        mUserConfigAllowed = builder.mUserConfigAllowed;
+        mAutoDetectionEnabled = builder.mAutoDetectionEnabled;
+    }
+
+    /** Returns a {@link TimeCapabilitiesAndConfig} objects based on configuration values. */
+    public TimeCapabilitiesAndConfig capabilitiesAndConfig() {
+        return new TimeCapabilitiesAndConfig(timeCapabilities(), timeConfiguration());
+    }
+
+    private TimeConfiguration timeConfiguration() {
+        return new TimeConfiguration.Builder()
+                .setAutoDetectionEnabled(mAutoDetectionEnabled)
+                .build();
+    }
+
+    private TimeCapabilities timeCapabilities() {
+        @CapabilityState int configureAutoTimeDetectionEnabledCapability =
+                mUserConfigAllowed
+                        ? CAPABILITY_POSSESSED
+                        : CAPABILITY_NOT_ALLOWED;
+
+        @CapabilityState int suggestTimeManuallyCapability =
+                mUserConfigAllowed
+                        ? CAPABILITY_POSSESSED
+                        : CAPABILITY_NOT_ALLOWED;
+
+        return new TimeCapabilities.Builder(UserHandle.of(mUserId))
+                .setConfigureAutoTimeDetectionEnabledCapability(
+                        configureAutoTimeDetectionEnabledCapability)
+                .setSuggestTimeManuallyCapability(suggestTimeManuallyCapability)
+                .build();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        ConfigurationInternal that = (ConfigurationInternal) o;
+        return mUserId == that.mUserId
+                && mUserConfigAllowed == that.mUserConfigAllowed
+                && mAutoDetectionEnabled == that.mAutoDetectionEnabled;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mUserId, mUserConfigAllowed, mAutoDetectionEnabled);
+    }
+
+    @Override
+    public String toString() {
+        return "ConfigurationInternal{"
+                + "mUserId=" + mUserId
+                + ", mUserConfigAllowed=" + mUserConfigAllowed
+                + ", mAutoDetectionEnabled=" + mAutoDetectionEnabled
+                + '}';
+    }
+
+    static final class Builder {
+        private final @UserIdInt int mUserId;
+        private boolean mUserConfigAllowed;
+        private boolean mAutoDetectionEnabled;
+
+        Builder(@UserIdInt int userId) {
+            mUserId = userId;
+        }
+
+        Builder setUserConfigAllowed(boolean userConfigAllowed) {
+            mUserConfigAllowed = userConfigAllowed;
+            return this;
+        }
+
+        Builder setAutoDetectionEnabled(boolean autoDetectionEnabled) {
+            mAutoDetectionEnabled = autoDetectionEnabled;
+            return this;
+        }
+
+        ConfigurationInternal build() {
+            return new ConfigurationInternal(this);
+        }
+    }
+
+}
diff --git a/services/core/java/com/android/server/timedetector/EnvironmentImpl.java b/services/core/java/com/android/server/timedetector/EnvironmentImpl.java
index 5cd1718..4f5e8fa 100644
--- a/services/core/java/com/android/server/timedetector/EnvironmentImpl.java
+++ b/services/core/java/com/android/server/timedetector/EnvironmentImpl.java
@@ -21,6 +21,7 @@
 import static com.android.server.timedetector.TimeDetectorStrategy.stringToOrigin;
 
 import android.annotation.NonNull;
+import android.annotation.UserIdInt;
 import android.app.AlarmManager;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -28,6 +29,8 @@
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.Settings;
 import android.util.Slog;
 
@@ -71,6 +74,7 @@
     @NonNull private final ContentResolver mContentResolver;
     @NonNull private final PowerManager.WakeLock mWakeLock;
     @NonNull private final AlarmManager mAlarmManager;
+    @NonNull private final UserManager mUserManager;
     @NonNull private final int[] mOriginPriorities;
 
     public EnvironmentImpl(@NonNull Context context) {
@@ -83,6 +87,8 @@
 
         mAlarmManager = Objects.requireNonNull(context.getSystemService(AlarmManager.class));
 
+        mUserManager = Objects.requireNonNull(context.getSystemService(UserManager.class));
+
         mSystemClockUpdateThresholdMillis =
                 SystemProperties.getInt("ro.sys.time_detector_update_diff",
                         SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT);
@@ -115,6 +121,14 @@
     }
 
     @Override
+    public ConfigurationInternal configurationInternal(@UserIdInt int userId) {
+        return new ConfigurationInternal.Builder(userId)
+                .setUserConfigAllowed(isUserConfigAllowed(userId))
+                .setAutoDetectionEnabled(isAutoTimeDetectionEnabled())
+                .build();
+    }
+
+    @Override
     public void acquireWakeLock() {
         if (mWakeLock.isHeld()) {
             Slog.wtf(TAG, "WakeLock " + mWakeLock + " already held");
@@ -150,6 +164,11 @@
         }
     }
 
+    private boolean isUserConfigAllowed(@UserIdInt int userId) {
+        UserHandle userHandle = UserHandle.of(userId);
+        return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_DATE_TIME, userHandle);
+    }
+
     private static int[] getOriginPriorities(@NonNull Context context) {
         String[] originStrings =
                 context.getResources().getStringArray(R.array.config_autoTimeSourcesPriority);
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index b210339..eefa045a 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -18,7 +18,10 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.time.ExternalTimeSuggestion;
+import android.app.time.TimeCapabilitiesAndConfig;
+import android.app.time.TimeConfiguration;
 import android.app.timedetector.GnssTimeSuggestion;
 import android.app.timedetector.ITimeDetectorService;
 import android.app.timedetector.ManualTimeSuggestion;
@@ -36,6 +39,7 @@
 import com.android.internal.util.DumpUtils;
 import com.android.server.FgThread;
 import com.android.server.SystemService;
+import com.android.server.timezonedetector.CallerIdentityInjector;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -71,6 +75,7 @@
     @NonNull private final Handler mHandler;
     @NonNull private final Context mContext;
     @NonNull private final TimeDetectorStrategy mTimeDetectorStrategy;
+    @NonNull private final CallerIdentityInjector mCallerIdentityInjector;
 
     private static TimeDetectorService create(@NonNull Context context) {
         TimeDetectorStrategyImpl.Environment environment = new EnvironmentImpl(context);
@@ -97,9 +102,42 @@
     @VisibleForTesting
     public TimeDetectorService(@NonNull Context context, @NonNull Handler handler,
             @NonNull TimeDetectorStrategy timeDetectorStrategy) {
+        this(context, handler, timeDetectorStrategy, CallerIdentityInjector.REAL);
+    }
+
+    @VisibleForTesting
+    public TimeDetectorService(@NonNull Context context, @NonNull Handler handler,
+            @NonNull TimeDetectorStrategy timeDetectorStrategy,
+            @NonNull CallerIdentityInjector callerIdentityInjector) {
         mContext = Objects.requireNonNull(context);
         mHandler = Objects.requireNonNull(handler);
         mTimeDetectorStrategy = Objects.requireNonNull(timeDetectorStrategy);
+        mCallerIdentityInjector = Objects.requireNonNull(callerIdentityInjector);
+    }
+
+    @Override
+    public TimeCapabilitiesAndConfig getCapabilitiesAndConfig() {
+        int userId = mCallerIdentityInjector.getCallingUserId();
+        return getTimeCapabilitiesAndConfig(userId);
+    }
+
+    private TimeCapabilitiesAndConfig getTimeCapabilitiesAndConfig(@UserIdInt int userId) {
+        enforceManageTimeDetectorPermission();
+
+        final long token = mCallerIdentityInjector.clearCallingIdentity();
+        try {
+            ConfigurationInternal configurationInternal =
+                    mTimeDetectorStrategy.getConfigurationInternal(userId);
+            return configurationInternal.capabilitiesAndConfig();
+        } finally {
+            mCallerIdentityInjector.restoreCallingIdentity(token);
+        }
+    }
+
+    @Override
+    public boolean updateConfiguration(TimeConfiguration timeConfiguration) {
+        // TODO(b/172891783) Add actual logic
+        return false;
     }
 
     @Override
@@ -193,4 +231,11 @@
                 android.Manifest.permission.SET_TIME,
                 "suggest time from external source");
     }
+
+    private void enforceManageTimeDetectorPermission() {
+        mContext.enforceCallingPermission(
+                android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION,
+                "manage time and time zone detection");
+    }
+
 }
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
index 792f372..cde66be 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.UserIdInt;
 import android.app.time.ExternalTimeSuggestion;
 import android.app.timedetector.GnssTimeSuggestion;
 import android.app.timedetector.ManualTimeSuggestion;
@@ -88,6 +89,9 @@
     /** Processes the suggested time from external sources. */
     void suggestExternalTime(@NonNull ExternalTimeSuggestion timeSuggestion);
 
+    /** Returns the configuration that controls time detector behaviour for specified user. */
+    ConfigurationInternal getConfigurationInternal(@UserIdInt int userId);
+
     /**
      * Handles the auto-time configuration changing For example, when the auto-time setting is
      * toggled on or off.
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
index 16e8632c..289d8d6 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -22,6 +22,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.AlarmManager;
 import android.app.time.ExternalTimeSuggestion;
 import android.app.timedetector.GnssTimeSuggestion;
@@ -155,6 +156,12 @@
          */
         @Origin int[] autoOriginPriorities();
 
+        /**
+         * Returns {@link ConfigurationInternal} for specified user.
+         */
+        @NonNull
+        ConfigurationInternal configurationInternal(@UserIdInt int userId);
+
         /** Acquire a suitable wake lock. Must be followed by {@link #releaseWakeLock()} */
         void acquireWakeLock();
 
@@ -267,6 +274,12 @@
     }
 
     @Override
+    @NonNull
+    public ConfigurationInternal getConfigurationInternal(@UserIdInt int userId) {
+        return mEnvironment.configurationInternal(userId);
+    }
+
+    @Override
     public synchronized void handleAutoTimeConfigChanged() {
         boolean enabled = mEnvironment.isAutoTimeDetectionEnabled();
         // When automatic time detection is enabled we update the system clock instantly if we can.
diff --git a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
index ee78a4e..b4aa201 100644
--- a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
+++ b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
@@ -16,10 +16,10 @@
 
 package com.android.server.timezonedetector;
 
-import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED;
-import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
-import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED;
-import static android.app.time.TimeZoneCapabilities.CAPABILITY_POSSESSED;
+import static android.app.time.Capabilities.CAPABILITY_NOT_ALLOWED;
+import static android.app.time.Capabilities.CAPABILITY_NOT_APPLICABLE;
+import static android.app.time.Capabilities.CAPABILITY_NOT_SUPPORTED;
+import static android.app.time.Capabilities.CAPABILITY_POSSESSED;
 
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
index 5d34dd7..c34a7d3 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
@@ -15,7 +15,7 @@
  */
 package com.android.server.timezonedetector;
 
-import static android.app.time.TimeZoneCapabilities.CAPABILITY_POSSESSED;
+import static android.app.time.Capabilities.CAPABILITY_POSSESSED;
 import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.MATCH_TYPE_EMULATOR_ZONE_ID;
 import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY;
 import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
diff --git a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
index 8dcc547..6ff8d6f 100644
--- a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
+++ b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
@@ -290,25 +290,6 @@
         maybeNotifyCallback();
     }
 
-    private void handleNetworkSuspended(@NonNull Network network, boolean isSuspended) {
-        mVcnContext.ensureRunningOnLooperThread();
-
-        if (!isSameNetwork(mRecordInProgress, network)) {
-            Slog.wtf(TAG, "Invalid update to isSuspended");
-            return;
-        }
-
-        final NetworkCapabilities newCaps =
-                new NetworkCapabilities(mRecordInProgress.getNetworkCapabilities());
-        if (isSuspended) {
-            newCaps.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
-        } else {
-            newCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
-        }
-
-        handleCapabilitiesChanged(network, newCaps);
-    }
-
     private void handlePropertiesChanged(
             @NonNull Network network, @NonNull LinkProperties linkProperties) {
         mVcnContext.ensureRunningOnLooperThread();
@@ -366,20 +347,11 @@
         @Override
         public void onCapabilitiesChanged(
                 @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) {
+            if (networkCapabilities.equals(mRecordInProgress.getNetworkCapabilities())) return;
             handleCapabilitiesChanged(network, networkCapabilities);
         }
 
         @Override
-        public void onNetworkSuspended(@NonNull Network network) {
-            handleNetworkSuspended(network, true /* isSuspended */);
-        }
-
-        @Override
-        public void onNetworkResumed(@NonNull Network network) {
-            handleNetworkSuspended(network, false /* isSuspended */);
-        }
-
-        @Override
         public void onLinkPropertiesChanged(
                 @NonNull Network network, @NonNull LinkProperties linkProperties) {
             handlePropertiesChanged(network, linkProperties);
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 69a153f..9589505 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -42,7 +42,6 @@
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkAgent;
-import android.net.NetworkAgent.ValidationStatus;
 import android.net.NetworkAgentConfig;
 import android.net.NetworkCapabilities;
 import android.net.RouteInfo;
@@ -1442,17 +1441,16 @@
                             caps,
                             lp,
                             Vcn.getNetworkScore(),
-                            new NetworkAgentConfig(),
+                            new NetworkAgentConfig.Builder().build(),
                             mVcnContext.getVcnNetworkProvider()) {
                         @Override
-                        public void unwanted() {
+                        public void onNetworkUnwanted() {
                             Slog.d(TAG, "NetworkAgent was unwanted");
                             teardownAsynchronously();
                         }
 
                         @Override
-                        public void onValidationStatus(
-                                @ValidationStatus int status, @Nullable Uri redirectUri) {
+                        public void onValidationStatus(int status, @Nullable Uri redirectUri) {
                             if (status == NetworkAgent.VALIDATION_STATUS_VALID) {
                                 clearFailedAttemptCounterAndSafeModeAlarm();
                             }
@@ -1798,8 +1796,10 @@
             lp.addDnsServer(addr);
         }
 
-        lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
-        lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
+        lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null /*gateway*/,
+                null /*iface*/, RouteInfo.RTN_UNICAST));
+        lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null /*gateway*/,
+                null /*iface*/, RouteInfo.RTN_UNICAST));
 
         lp.setMtu(gatewayConnectionConfig.getMaxMtu());
 
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index d361a8c..4517ef5 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -438,10 +438,6 @@
     final String packageName;
     // the intent component, or target of an alias.
     final ComponentName mActivityComponent;
-    // Has a wallpaper window as a background.
-    // TODO: Rename to mHasWallpaper and also see if it possible to combine this with the
-    // mOccludesParent field.
-    final boolean hasWallpaper;
     // Input application handle used by the input dispatcher.
     private InputApplicationHandle mInputApplicationHandle;
 
@@ -1104,19 +1100,25 @@
             return;
         }
 
-        boolean isLetterboxed = isLetterboxed(mainWin);
-        pw.println(prefix + "isLetterboxed=" + isLetterboxed);
-        if (!isLetterboxed) {
+        boolean areBoundsLetterboxed = mainWin.isLetterboxedAppWindow();
+        pw.println(prefix + "areBoundsLetterboxed=" + areBoundsLetterboxed);
+        if (!areBoundsLetterboxed) {
             return;
         }
 
         pw.println(prefix + "  letterboxReason=" + getLetterboxReasonString(mainWin));
+        pw.println(prefix + "  letterboxAspectRatio=" + computeAspectRatio(getBounds()));
+
+        boolean isLetterboxUiShown = isLetterboxed(mainWin);
+        pw.println(prefix + "isLetterboxUiShown=" + isLetterboxUiShown);
+
+        if (!isLetterboxUiShown) {
+            return;
+        }
         pw.println(prefix + "  letterboxBackgroundColor=" + Integer.toHexString(
                 getLetterboxBackgroundColor().toArgb()));
         pw.println(prefix + "  letterboxBackgroundType="
                 + letterboxBackgroundTypeToString(mWmService.getLetterboxBackgroundType()));
-        pw.println(prefix + "  letterboxAspectRatio="
-                + computeAspectRatio(getBounds()));
     }
 
     /**
@@ -1463,9 +1465,17 @@
                 "Unexpected letterbox background type: " + letterboxBackgroundType);
     }
 
-    /** @return {@code true} when main window is letterboxed and activity isn't transparent. */
-    private boolean isLetterboxed(WindowState mainWindow) {
-        return mainWindow.isLetterboxedAppWindow() && fillsParent();
+    /**
+     * @return {@code true} when the main window is letterboxed, this activity isn't transparent
+     * and doesn't show a wallpaper.
+     */
+    @VisibleForTesting
+    boolean isLetterboxed(WindowState mainWindow) {
+        return mainWindow.isLetterboxedAppWindow() && fillsParent()
+                // Check for FLAG_SHOW_WALLPAPER explicitly instead of using
+                // WindowContainer#showWallpaper because the later will return true when this
+                // activity is using blurred wallpaper for letterbox backgroud.
+                && (mainWindow.mAttrs.flags & FLAG_SHOW_WALLPAPER) == 0;
     }
 
     private void updateRoundedCorners(WindowState mainWindow) {
@@ -1655,11 +1665,12 @@
                 realTheme, com.android.internal.R.styleable.Window, mUserId);
 
         if (ent != null) {
-            mOccludesParent = !ActivityInfo.isTranslucentOrFloating(ent.array);
-            hasWallpaper = ent.array.getBoolean(R.styleable.Window_windowShowWallpaper, false);
+            mOccludesParent = !ActivityInfo.isTranslucentOrFloating(ent.array)
+                    // This style is propagated to the main window attributes with
+                    // FLAG_SHOW_WALLPAPER from PhoneWindow#generateLayout.
+                    || ent.array.getBoolean(R.styleable.Window_windowShowWallpaper, false);
             noDisplay = ent.array.getBoolean(R.styleable.Window_windowNoDisplay, false);
         } else {
-            hasWallpaper = false;
             noDisplay = false;
         }
 
@@ -2114,6 +2125,10 @@
         if (snapshot == null) {
             return false;
         }
+        if (!snapshot.getTopActivityComponent().equals(mActivityComponent)) {
+            // Obsoleted snapshot.
+            return false;
+        }
         final int rotation = mDisplayContent.rotationForActivityInDifferentOrientation(this);
         final int targetRotation = rotation != ROTATION_UNDEFINED
                 // The display may rotate according to the orientation of this activity.
@@ -2247,6 +2262,9 @@
                 // Go ahead and cancel the request.
                 ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Clearing startingData for token=%s", this);
                 mStartingData = null;
+                // Clean surface up since we don't want the window to be added back, so we don't
+                // need to keep the surface to remove it.
+                mStartingSurface = null;
             }
             return;
         }
@@ -2461,7 +2479,7 @@
         if (!includingFinishing && finishing) {
             return false;
         }
-        return mOccludesParent;
+        return mOccludesParent || showWallpaper();
     }
 
     boolean setOccludesParent(boolean occludesParent) {
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 59d40cf..18e5552 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1429,6 +1429,7 @@
                 + "; allowBackgroundActivityStart: " + allowBackgroundActivityStart
                 + "; intent: " + intent
                 + "; callerApp: " + callerApp
+                + "; inVisibleTask: " + (callerApp != null && callerApp.hasActivityInVisibleTask())
                 + "]");
         // log aborted activity start to TRON
         if (mService.isActivityStartsLoggingEnabled()) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index e858fe1..060323c 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -32,6 +32,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.service.voice.IVoiceInteractionSession;
+import android.util.Pair;
 import android.util.proto.ProtoOutputStream;
 import android.window.TaskSnapshot;
 
@@ -162,10 +163,10 @@
             IVoiceInteractor mInteractor);
 
     /**
-     * Returns the top activity from each of the currently visible root tasks. The first entry
-     * will be the focused activity.
+     * Returns the top activity from each of the currently visible root tasks, and the related task
+     * id. The first entry will be the focused activity.
      */
-    public abstract List<IBinder> getTopVisibleActivities();
+    public abstract List<Pair<IBinder, Integer>> getTopVisibleActivities();
 
     /**
      * Returns whether {@code uid} has any resumed activity.
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 52d110c..09f5c93 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -215,6 +215,7 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.TimeUtils;
@@ -5074,7 +5075,7 @@
         }
 
         @Override
-        public List<IBinder> getTopVisibleActivities() {
+        public List<Pair<IBinder, Integer>> getTopVisibleActivities() {
             synchronized (mGlobalLock) {
                 return mRootWindowContainer.getTopVisibleActivities();
             }
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 5b685b4..99289e0 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -1305,7 +1305,7 @@
         if (isTransitionSet()) {
             clear();
             mNextAppTransitionType = NEXT_TRANSIT_TYPE_REMOTE;
-            mRemoteAnimationController = new RemoteAnimationController(mService,
+            mRemoteAnimationController = new RemoteAnimationController(mService, mDisplayContent,
                     remoteAnimationAdapter, mHandler);
         }
     }
diff --git a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
index ab1ed67..71a10df 100644
--- a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
+++ b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
@@ -70,9 +70,10 @@
     }
 
     boolean areBackgroundActivityStartsAllowed(int pid, int uid, String packageName,
-            boolean appSwitchAllowed, boolean isCheckingForFgsStart, boolean hasVisibleActivities,
-            boolean hasBackgroundActivityStartPrivileges, long lastStopAppSwitchesTime,
-            long lastActivityLaunchTime, long lastActivityFinishTime) {
+            boolean appSwitchAllowed, boolean isCheckingForFgsStart,
+            boolean hasActivityInVisibleTask, boolean hasBackgroundActivityStartPrivileges,
+            long lastStopAppSwitchesTime, long lastActivityLaunchTime,
+            long lastActivityFinishTime) {
         // If app switching is not allowed, we ignore all the start activity grace period
         // exception so apps cannot start itself in onPause() after pressing home button.
         if (appSwitchAllowed) {
@@ -110,7 +111,7 @@
             return true;
         }
         // Allow if the caller has an activity in any foreground task.
-        if (appSwitchAllowed && hasVisibleActivities) {
+        if (appSwitchAllowed && hasActivityInVisibleTask) {
             if (DEBUG_ACTIVITY_STARTS) {
                 Slog.d(TAG, "[Process(" + pid
                         + ")] Activity start allowed: process has activity in foreground task");
diff --git a/services/core/java/com/android/server/wm/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java
index 28a509b..0ec0142 100644
--- a/services/core/java/com/android/server/wm/CompatModePackages.java
+++ b/services/core/java/com/android/server/wm/CompatModePackages.java
@@ -74,45 +74,59 @@
     /**
      * CompatModePackages#DOWNSCALED is the gatekeeper of all per-app buffer downscaling
      * changes.  Disabling this change will prevent the following scaling factors from working:
-     * CompatModePackages#DOWNSCALE_87_5
-     * CompatModePackages#DOWNSCALE_75
-     * CompatModePackages#DOWNSCALE_62_5
+     * CompatModePackages#DOWNSCALE_90
+     * CompatModePackages#DOWNSCALE_80
+     * CompatModePackages#DOWNSCALE_70
+     * CompatModePackages#DOWNSCALE_60
      * CompatModePackages#DOWNSCALE_50
      *
      * If CompatModePackages#DOWNSCALED is enabled for an app package, then the app will be forcibly
-     * resized to the highest enabled scaling factor e.g. 87.5% if both 87.5% and 75% were
-     * enabled.
+     * resized to the highest enabled scaling factor e.g. 80% if both 80% and 70% were enabled.
      */
     @ChangeId
     @Disabled
-    private static final long DOWNSCALED = 168419799L;
+    @Overridable
+    public static final long DOWNSCALED = 168419799L;
 
     /**
      * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
-     * CompatModePackages#DOWNSCALE_87_5 for a package will force the app to assume it's
-     * running on a display with 87.5% the vertical and horizontal resolution of the real display.
+     * CompatModePackages#DOWNSCALE_90 for a package will force the app to assume it's
+     * running on a display with 90% the vertical and horizontal resolution of the real display.
      */
     @ChangeId
     @Disabled
-    private static final long DOWNSCALE_87_5 = 176926753L;
+    @Overridable
+    public static final long DOWNSCALE_90 = 182811243L;
 
     /**
      * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
-     * CompatModePackages#DOWNSCALE_75 for a package will force the app to assume it's
-     * running on a display with 75% the vertical and horizontal resolution of the real display.
+     * CompatModePackages#DOWNSCALE_80 for a package will force the app to assume it's
+     * running on a display with 80% the vertical and horizontal resolution of the real display.
      */
     @ChangeId
     @Disabled
-    private static final long DOWNSCALE_75 = 176926829L;
+    @Overridable
+    public static final long DOWNSCALE_80 = 176926753L;
 
     /**
      * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
-     * CompatModePackages#DOWNSCALE_62_5 for a package will force the app to assume it's
-     * running on a display with 62.5% the vertical and horizontal resolution of the real display.
+     * CompatModePackages#DOWNSCALE_70 for a package will force the app to assume it's
+     * running on a display with 70% the vertical and horizontal resolution of the real display.
      */
     @ChangeId
     @Disabled
-    private static final long DOWNSCALE_62_5 = 176926771L;
+    @Overridable
+    public static final long DOWNSCALE_70 = 176926829L;
+
+    /**
+     * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
+     * CompatModePackages#DOWNSCALE_60 for a package will force the app to assume it's
+     * running on a display with 60% the vertical and horizontal resolution of the real display.
+     */
+    @ChangeId
+    @Disabled
+    @Overridable
+    public static final long DOWNSCALE_60 = 176926771L;
 
     /**
      * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
@@ -121,7 +135,8 @@
      */
     @ChangeId
     @Disabled
-    private static final long DOWNSCALE_50 = 176926741L;
+    @Overridable
+    public static final long DOWNSCALE_50 = 176926741L;
 
     /**
      * On Android TV applications that target pre-S are not expecting to receive a Window larger
@@ -273,17 +288,20 @@
     float getCompatScale(String packageName, int uid) {
         final UserHandle userHandle = UserHandle.getUserHandleForUid(uid);
         if (CompatChanges.isChangeEnabled(DOWNSCALED, packageName, userHandle)) {
-            if (CompatChanges.isChangeEnabled(DOWNSCALE_87_5, packageName, userHandle)) {
-                return 8f / 7f; // 1.14285714286
+            if (CompatChanges.isChangeEnabled(DOWNSCALE_90, packageName, userHandle)) {
+                return 1f / 0.9f;
             }
-            if (CompatChanges.isChangeEnabled(DOWNSCALE_75, packageName, userHandle)) {
-                return 4f / 3f; // 1.333333333
+            if (CompatChanges.isChangeEnabled(DOWNSCALE_80, packageName, userHandle)) {
+                return 1f / 0.8f;
             }
-            if (CompatChanges.isChangeEnabled(DOWNSCALE_62_5, packageName, userHandle)) {
-                return /* 1 / 0.625 */ 1.6f;
+            if (CompatChanges.isChangeEnabled(DOWNSCALE_70, packageName, userHandle)) {
+                return 1f / 0.7f;
+            }
+            if (CompatChanges.isChangeEnabled(DOWNSCALE_60, packageName, userHandle)) {
+                return 1f / 0.6f;
             }
             if (CompatChanges.isChangeEnabled(DOWNSCALE_50, packageName, userHandle)) {
-                return /* 1 / 0.5 */ 2f;
+                return 1f / 0.5f;
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 95b2b5d..6d24105 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1428,7 +1428,8 @@
             computeScreenConfiguration(config);
         } else if (currentConfig != null
                 // If waiting for a remote rotation, don't prematurely update configuration.
-                && !mDisplayRotation.isWaitingForRemoteRotation()) {
+                && !(mDisplayRotation.isWaitingForRemoteRotation()
+                        || mAtmService.getTransitionController().isCollecting(this))) {
             // No obvious action we need to take, but if our current state mismatches the
             // activity manager's, update it, disregarding font scale, which should remain set
             // to the value of the previous configuration.
@@ -1470,6 +1471,12 @@
         return mDisplayRotation.updateOrientation(orientation, forceUpdate);
     }
 
+    @Override
+    boolean isSyncFinished() {
+        if (mDisplayRotation.isWaitingForRemoteRotation()) return false;
+        return super.isSyncFinished();
+    }
+
     /**
      * Returns a valid rotation if the activity can use different orientation than the display.
      * Otherwise {@link #ROTATION_UNDEFINED}.
@@ -1763,7 +1770,7 @@
      * Update rotation of the display.
      *
      * @return {@code true} if the rotation has been changed.  In this case YOU MUST CALL
-     *         {@link #sendNewConfiguration} TO UNFREEZE THE SCREEN.
+     *         {@link #sendNewConfiguration} TO UNFREEZE THE SCREEN unless using Shell transitions.
      */
     boolean updateRotationUnchecked() {
         return mDisplayRotation.updateRotationUnchecked(false /* forceUpdate */);
@@ -1778,8 +1785,12 @@
      */
     private void applyRotation(final int oldRotation, final int rotation) {
         mDisplayRotation.applyCurrentRotation(rotation);
-        final boolean rotateSeamlessly = mDisplayRotation.isRotatingSeamlessly();
-        final Transaction transaction = getPendingTransaction();
+        final boolean shellTransitions =
+                mWmService.mAtmService.getTransitionController().getTransitionPlayer() != null;
+        final boolean rotateSeamlessly =
+                mDisplayRotation.isRotatingSeamlessly() && !shellTransitions;
+        final Transaction transaction =
+                shellTransitions ? getSyncTransaction() : getPendingTransaction();
         ScreenRotationAnimation screenRotationAnimation = rotateSeamlessly
                 ? null : getRotationAnimation();
         // We need to update our screen size information to match the new rotation. If the rotation
@@ -1795,9 +1806,11 @@
             screenRotationAnimation.setRotation(transaction, rotation);
         }
 
-        forAllWindows(w -> {
-            w.seamlesslyRotateIfAllowed(transaction, oldRotation, rotation, rotateSeamlessly);
-        }, true /* traverseTopToBottom */);
+        if (!shellTransitions) {
+            forAllWindows(w -> {
+                w.seamlesslyRotateIfAllowed(transaction, oldRotation, rotation, rotateSeamlessly);
+            }, true /* traverseTopToBottom */);
+        }
 
         mWmService.mDisplayManagerInternal.performTraversal(transaction);
         scheduleAnimation();
@@ -4573,6 +4586,12 @@
         return mWmService.makeSurfaceBuilder(mSession).setParent(getOverlayLayer());
     }
 
+    @Override
+    public SurfaceControl.Builder makeAnimationLeash() {
+        return mWmService.makeSurfaceBuilder(mSession).setParent(mSurfaceControl)
+                .setContainerLayer();
+    }
+
     /**
      * Reparents the given surface to {@link #mOverlayLayer} SurfaceControl.
      */
@@ -5919,4 +5938,9 @@
         return mDisplayAreaPolicy.getDisplayAreaForWindowToken(windowType, options,
                 ownerCanManageAppToken, roundedCornerOverlay);
     }
+
+    @Override
+    DisplayContent asDisplayContent() {
+        return this;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 5df1355..d0e4c40 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -22,6 +22,7 @@
 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT;
 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
+import static android.view.WindowManager.TRANSIT_CHANGE;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
@@ -408,8 +409,11 @@
      *         THE SCREEN.
      */
     boolean updateRotationUnchecked(boolean forceUpdate) {
+        final boolean useShellTransitions =
+                mService.mAtmService.getTransitionController().getTransitionPlayer() != null;
+
         final int displayId = mDisplayContent.getDisplayId();
-        if (!forceUpdate) {
+        if (!forceUpdate && !useShellTransitions) {
             if (mDeferredRotationPauseCount > 0) {
                 // Rotation updates have been paused temporarily. Defer the update until updates
                 // have been resumed.
@@ -472,6 +476,12 @@
             return false;
         }
 
+        final Transition t = (useShellTransitions
+                && !mService.mAtmService.getTransitionController().isCollecting())
+                ? mService.mAtmService.getTransitionController().createTransition(TRANSIT_CHANGE)
+                : null;
+        mService.mAtmService.getTransitionController().collect(mDisplayContent);
+
         ProtoLog.v(WM_DEBUG_ORIENTATION,
                 "Display id=%d rotation changed to %d from %d, lastOrientation=%d",
                         displayId, rotation, oldRotation, lastOrientation);
@@ -484,6 +494,20 @@
 
         mDisplayContent.setLayoutNeeded();
 
+        if (useShellTransitions) {
+            if (t != null) {
+                // This created its own transition, so send a start request.
+                mService.mAtmService.getTransitionController().requestStartTransition(
+                        t, null /* trigger */, null /* remote */);
+            } else {
+                // Use remote-rotation infra since the transition has already been requested
+                // TODO(shell-transitions): Remove this once lifecycle management can cover all
+                //                          rotation cases.
+                startRemoteRotation(oldRotation, mRotation);
+            }
+            return true;
+        }
+
         mService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
         mService.mH.sendNewMessageDelayed(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT,
                 mDisplayContent, WINDOW_FREEZE_TIMEOUT_DURATION);
@@ -504,6 +528,19 @@
     }
 
     /**
+     * Utility to get a rotating displaycontent from a Transition.
+     * @return null if the transition doesn't contain a rotating display.
+     */
+    static DisplayContent getDisplayFromTransition(Transition transition) {
+        for (int i = transition.mParticipants.size() - 1; i >= 0; --i) {
+            final WindowContainer wc = transition.mParticipants.valueAt(i);
+            if (!(wc instanceof DisplayContent)) continue;
+            return (DisplayContent) wc;
+        }
+        return null;
+    }
+
+    /**
      * A Remote rotation is when we are waiting for some registered (remote)
      * {@link IDisplayWindowRotationController} to calculate and return some hierarchy operations
      *  to perform in sync with the rotation.
@@ -537,6 +574,22 @@
             }
             mService.mH.removeCallbacks(mDisplayRotationHandlerTimeout);
             mIsWaitingForRemoteRotation = false;
+
+            if (mService.mAtmService.getTransitionController().getTransitionPlayer() != null) {
+                if (!mService.mAtmService.getTransitionController().isCollecting()) {
+                    throw new IllegalStateException("Trying to rotate outside a transition");
+                }
+                mService.mAtmService.getTransitionController().collect(mDisplayContent);
+                // Go through all tasks and collect them before the rotation
+                // TODO(shell-transitions): move collect() to onConfigurationChange once wallpaper
+                //       handling is synchronized.
+                mDisplayContent.forAllTasks(task -> {
+                    if (task.isVisible()) {
+                        mService.mAtmService.getTransitionController().collect(task);
+                    }
+                });
+                mDisplayContent.getInsetsStateController().addProvidersToTransition();
+            }
             mService.mAtmService.deferWindowLayout();
             try {
                 mDisplayContent.sendNewConfiguration();
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index 1120a07..d12d07a 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -283,11 +283,7 @@
                 return;
             }
 
-            if (keepHandling) {
-                mDragState.notifyMoveLocked(newX, newY);
-            } else {
-                mDragState.notifyDropLocked(newX, newY);
-            }
+            mDragState.updateDragSurfaceLocked(keepHandling, newX, newY);
         }
     }
 
@@ -330,6 +326,12 @@
         mDragState = null;
     }
 
+    void reportDropWindow(IBinder token, float x, float y) {
+        synchronized (mService.mGlobalLock) {
+            mDragState.reportDropWindowLock(token, x, y);
+        }
+    }
+
     private class DragHandler extends Handler {
         /**
          * Lock for window manager.
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 08d5e80..fd4bbd7 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -109,7 +109,6 @@
     float mCurrentX, mCurrentY;
     float mThumbOffsetX, mThumbOffsetY;
     InputInterceptor mInputInterceptor;
-    WindowState mTargetWindow;
     ArrayList<WindowState> mNotifiedWindows;
     boolean mDragInProgress;
     /**
@@ -217,18 +216,18 @@
                     x = mCurrentX;
                     y = mCurrentY;
                 }
-                DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED,
+                DragEvent event = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED,
                         x, y, mThumbOffsetX, mThumbOffsetY, null, null, null, null, null,
                         mDragResult);
                 try {
-                    ws.mClient.dispatchDragEvent(evt);
+                    ws.mClient.dispatchDragEvent(event);
                 } catch (RemoteException e) {
                     Slog.w(TAG_WM, "Unable to drag-end window " + ws);
                 }
                 // if the current window is in the same process,
                 // the dispatch has already recycled the event
                 if (myPid != ws.mSession.mPid) {
-                    evt.recycle();
+                    event.recycle();
                 }
             }
             mNotifiedWindows.clear();
@@ -270,6 +269,68 @@
         mDragDropController.onDragStateClosedLocked(this);
     }
 
+    /**
+     * Notify the drop target and tells it about the data. If the drop event is not sent to the
+     * target, invokes {@code endDragLocked} immediately.
+     */
+    void reportDropWindowLock(IBinder token, float x, float y) {
+        if (mAnimator != null) {
+            return;
+        }
+
+        final WindowState touchedWin = mService.mInputToWindowMap.get(token);
+        if (!isWindowNotified(touchedWin)) {
+            // "drop" outside a valid window -- no recipient to apply a
+            // timeout to, and we can send the drag-ended message immediately.
+            mDragResult = false;
+            endDragLocked();
+            if (DEBUG_DRAG) Slog.d(TAG_WM, "Drop outside a valid window " + touchedWin);
+            return;
+        }
+
+        if (DEBUG_DRAG) Slog.d(TAG_WM, "sending DROP to " + touchedWin);
+
+        final int targetUserId = UserHandle.getUserId(touchedWin.getOwningUid());
+
+        final DragAndDropPermissionsHandler dragAndDropPermissions;
+        if ((mFlags & View.DRAG_FLAG_GLOBAL) != 0 && (mFlags & DRAG_FLAGS_URI_ACCESS) != 0
+                && mData != null) {
+            dragAndDropPermissions = new DragAndDropPermissionsHandler(mService.mGlobalLock,
+                    mData,
+                    mUid,
+                    touchedWin.getOwningPackage(),
+                    mFlags & DRAG_FLAGS_URI_PERMISSIONS,
+                    mSourceUserId,
+                    targetUserId);
+        } else {
+            dragAndDropPermissions = null;
+        }
+        if (mSourceUserId != targetUserId) {
+            if (mData != null) {
+                mData.fixUris(mSourceUserId);
+            }
+        }
+        final int myPid = Process.myPid();
+        final IBinder clientToken = touchedWin.mClient.asBinder();
+        final DragEvent event = obtainDragEvent(DragEvent.ACTION_DROP, x, y,
+                true /* includeData */, targetInterceptsGlobalDrag(touchedWin),
+                dragAndDropPermissions);
+        try {
+            touchedWin.mClient.dispatchDragEvent(event);
+
+            // 5 second timeout for this window to respond to the drop
+            mDragDropController.sendTimeoutMessage(MSG_DRAG_END_TIMEOUT, clientToken);
+        } catch (RemoteException e) {
+            Slog.w(TAG_WM, "can't send drop notification to win " + touchedWin);
+            endDragLocked();
+        } finally {
+            if (myPid != touchedWin.mSession.mPid) {
+                event.recycle();
+            }
+        }
+        mToken = clientToken;
+    }
+
     class InputInterceptor {
         InputChannel mClientChannel;
         DragInputEventReceiver mInputEventReceiver;
@@ -397,9 +458,9 @@
             ClipDescription desc, ClipData data) {
         final boolean interceptsGlobalDrag = targetInterceptsGlobalDrag(newWin);
         if (mDragInProgress && isValidDropTarget(newWin, interceptsGlobalDrag)) {
-            DragEvent event = obtainDragEvent(newWin, DragEvent.ACTION_DRAG_STARTED,
-                    touchX, touchY, mThumbOffsetX, mThumbOffsetY, null, desc,
-                    interceptsGlobalDrag ? data : null, null, null, false);
+            DragEvent event = obtainDragEvent(DragEvent.ACTION_DRAG_STARTED, touchX, touchY,
+                    interceptsGlobalDrag, false /* includeDragSurface */,
+                    null /* dragAndDropPermission */);
             try {
                 newWin.mClient.dispatchDragEvent(event);
                 // track each window that we've notified that the drag is starting
@@ -501,13 +562,17 @@
         mAnimator = createCancelAnimationLocked();
     }
 
-    void notifyMoveLocked(float x, float y) {
+    void updateDragSurfaceLocked(boolean keepHandling, float x, float y) {
         if (mAnimator != null) {
             return;
         }
         mCurrentX = x;
         mCurrentY = y;
 
+        if (!keepHandling) {
+            return;
+        }
+
         // Move the surface to the given touch
         if (SHOW_LIGHT_TRANSACTIONS) {
             Slog.i(TAG_WM, ">>> OPEN TRANSACTION notifyMoveLocked");
@@ -518,71 +583,6 @@
     }
 
     /**
-     * Finds the drop target and tells it about the data. If the drop event is not sent to the
-     * target, invokes {@code endDragLocked} immediately.
-     */
-    void notifyDropLocked(float x, float y) {
-        if (mAnimator != null) {
-            return;
-        }
-        mCurrentX = x;
-        mCurrentY = y;
-
-        final WindowState touchedWin = mDisplayContent.getTouchableWinAtPointLocked(x, y);
-
-        if (!isWindowNotified(touchedWin)) {
-            // "drop" outside a valid window -- no recipient to apply a
-            // timeout to, and we can send the drag-ended message immediately.
-            mDragResult = false;
-            endDragLocked();
-            return;
-        }
-
-        if (DEBUG_DRAG) Slog.d(TAG_WM, "sending DROP to " + touchedWin);
-
-        final int targetUserId = UserHandle.getUserId(touchedWin.getOwningUid());
-
-        final DragAndDropPermissionsHandler dragAndDropPermissions;
-        if ((mFlags & View.DRAG_FLAG_GLOBAL) != 0 && (mFlags & DRAG_FLAGS_URI_ACCESS) != 0
-                && mData != null) {
-            dragAndDropPermissions = new DragAndDropPermissionsHandler(mService.mGlobalLock,
-                    mData,
-                    mUid,
-                    touchedWin.getOwningPackage(),
-                    mFlags & DRAG_FLAGS_URI_PERMISSIONS,
-                    mSourceUserId,
-                    targetUserId);
-        } else {
-            dragAndDropPermissions = null;
-        }
-        if (mSourceUserId != targetUserId){
-            if (mData != null) {
-                mData.fixUris(mSourceUserId);
-            }
-        }
-        final int myPid = Process.myPid();
-        final IBinder token = touchedWin.mClient.asBinder();
-        final DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DROP, x, y,
-                mThumbOffsetX, mThumbOffsetY, null, null, mData,
-                targetInterceptsGlobalDrag(touchedWin) ? mSurfaceControl : null,
-                dragAndDropPermissions, false);
-        try {
-            touchedWin.mClient.dispatchDragEvent(evt);
-
-            // 5 second timeout for this window to respond to the drop
-            mDragDropController.sendTimeoutMessage(MSG_DRAG_END_TIMEOUT, token);
-        } catch (RemoteException e) {
-            Slog.w(TAG_WM, "can't send drop notification to win " + touchedWin);
-            endDragLocked();
-        } finally {
-            if (myPid != touchedWin.mSession.mPid) {
-                evt.recycle();
-            }
-        }
-        mToken = token;
-    }
-
-    /**
      * Returns true if it has sent DRAG_STARTED broadcast out but has not been sent DRAG_END
      * broadcast.
      */
@@ -590,14 +590,12 @@
         return mDragInProgress;
     }
 
-    private static DragEvent obtainDragEvent(WindowState win, int action, float x, float y,
-            float offsetX, float offsetY, Object localState, ClipDescription description,
-            ClipData data, SurfaceControl dragSurface,
-            IDragAndDropPermissions dragAndDropPermissions, boolean result) {
-        final float winX = win.translateToWindowX(x);
-        final float winY = win.translateToWindowY(y);
-        return DragEvent.obtain(action, winX, winY, offsetX, offsetY, localState, description, data,
-                dragSurface, dragAndDropPermissions, result);
+    private DragEvent obtainDragEvent(int action, float x, float y, boolean includeData,
+            boolean includeDragSurface, IDragAndDropPermissions dragAndDropPermissions) {
+        return DragEvent.obtain(action, x, y, mThumbOffsetX, mThumbOffsetY,
+                null  /* localState */, mDataDescription,
+                includeData ? mData : null, includeDragSurface ? mSurfaceControl : null,
+                dragAndDropPermissions, false /* result */);
     }
 
     private ValueAnimator createReturnAnimationLocked() {
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index 6e89581..84616c0 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -229,6 +229,12 @@
                 mService::reportFocusChanged, oldToken, newToken));
     }
 
+    @Override
+    public void notifyDropWindow(IBinder token, float x, float y) {
+        mService.mH.sendMessage(PooledLambda.obtainMessage(
+                mService.mDragDropController::reportDropWindow, token, x, y));
+    }
+
     /** Waits until the built-in input devices have been configured. */
     public boolean waitForInputDevicesReady(long timeoutMillis) {
         synchronized (mInputDevicesReadyMonitor) {
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 986f768..465042d 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -492,8 +492,11 @@
                 mAnimatingShown = show;
 
                 final InsetsState state = getInsetsForWindow(mFocusedWin);
+
+                // We are about to playing the default animation. Passing a null frame indicates
+                // the controlled types should be animated regardless of the frame.
                 mAnimationControl = new InsetsAnimationControlImpl(controls,
-                        state.getDisplayFrame(), state, mListener, typesReady, this,
+                        null /* frame */, state, mListener, typesReady, this,
                         mListener.getDurationMs(), InsetsController.SYSTEM_BARS_INTERPOLATOR,
                         show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE, null /* translator */);
                 SurfaceAnimationThread.getHandler().post(
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 45c4233..38ad4f0 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -43,6 +43,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.graphics.Insets;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.util.proto.ProtoOutputStream;
@@ -102,7 +103,8 @@
         mSource = source;
         mDisplayContent = displayContent;
         mStateController = stateController;
-        mFakeControl = new InsetsSourceControl(source.getType(), null /* leash */, new Point());
+        mFakeControl = new InsetsSourceControl(
+                source.getType(), null /* leash */, new Point(), Insets.NONE);
 
         switch (source.getType()) {
             case ITYPE_STATUS_BAR:
@@ -246,8 +248,10 @@
         setServerVisible(mWin.wouldBeVisibleIfPolicyIgnored() && mWin.isVisibleByPolicy());
         updateSourceFrame();
         if (mControl != null) {
+            boolean changed = false;
             final Point position = getWindowFrameSurfacePosition();
             if (mControl.setSurfacePosition(position.x, position.y) && mControlTarget != null) {
+                changed = true;
                 if (!mWin.getWindowFrames().didFrameSizeChange()) {
                     updateLeashPosition(-1 /* frameNumber */);
                 } else if (mWin.mInRelayout) {
@@ -255,6 +259,14 @@
                 } else {
                     mWin.mPendingPositionChanged = this;
                 }
+            }
+            final Insets insetsHint = mSource.calculateInsets(
+                    mWin.getBounds(), true /* ignoreVisibility */);
+            if (!insetsHint.equals(mControl.getInsetsHint())) {
+                changed = true;
+                mControl.setInsetsHint(insetsHint);
+            }
+            if (changed) {
                 mStateController.notifyControlChanged(mControlTarget);
             }
         }
@@ -343,7 +355,8 @@
         final SurfaceControl leash = mAdapter.mCapturedLeash;
         mControlTarget = target;
         updateVisibility();
-        mControl = new InsetsSourceControl(mSource.getType(), leash, surfacePosition);
+        mControl = new InsetsSourceControl(mSource.getType(), leash, surfacePosition,
+                mSource.calculateInsets(mWin.getBounds(), true /* ignoreVisibility */));
         ProtoLog.d(WM_DEBUG_IME,
                 "InsetsSource Control %s for target %s", mControl, mControlTarget);
     }
@@ -418,7 +431,7 @@
                 // to the client in case that the client applies its transaction sooner than ours
                 // that we could unexpectedly overwrite the surface state.
                 return new InsetsSourceControl(mControl.getType(), null /* leash */,
-                        mControl.getSurfacePosition());
+                        mControl.getSurfacePosition(), mControl.getInsetsHint());
             }
             return mControl;
         }
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index a971794..b6057c6 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -248,6 +248,16 @@
         return result;
     }
 
+    public void addProvidersToTransition() {
+        for (int i = mProviders.size() - 1; i >= 0; --i) {
+            final InsetsSourceProvider p = mProviders.valueAt(i);
+            if (p == null) continue;
+            final WindowContainer wc = p.mWin;
+            if (wc == null) continue;
+            mDisplayContent.mAtmService.getTransitionController().collect(wc);
+        }
+    }
+
     /**
      * @return The provider of a specific type.
      */
diff --git a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
index f0629fa..520bd8b 100644
--- a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
@@ -126,7 +126,7 @@
         /**
          * @return {@code true} if we need to wake-up SurfaceFlinger earlier during this animation.
          *
-         * @see Transaction#setEarlyWakeup
+         * @see Transaction#setEarlyWakeupStart and Transaction#setEarlyWakeupEnd
          */
         default boolean needsEarlyWakeup() { return false; }
 
diff --git a/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java b/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
index 5d6d513..4ab5cd6 100644
--- a/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
@@ -16,6 +16,12 @@
 
 package com.android.server.wm;
 
+import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
+import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_TO_FRONT;
+import static android.view.WindowManager.TRANSIT_OLD_WALLPAPER_CLOSE;
+
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_REMOTE_ANIMATIONS;
 import static com.android.server.wm.AnimationAdapterProto.REMOTE;
 import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
@@ -26,6 +32,7 @@
 import android.util.proto.ProtoOutputStream;
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
+import android.view.WindowManager;
 
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.server.policy.WindowManagerPolicy;
@@ -35,9 +42,11 @@
 
 class NonAppWindowAnimationAdapter implements AnimationAdapter {
 
-    private final WindowState mWindow;
+    private final WindowContainer mWindowContainer;
     private RemoteAnimationTarget mTarget;
     private SurfaceControl mCapturedLeash;
+    private SurfaceAnimator.OnAnimationFinishedCallback mCapturedLeashFinishCallback;
+    private @SurfaceAnimator.AnimationType int mLastAnimationType;
 
     private long mDurationHint;
     private long mStatusBarTransitionDelay;
@@ -47,21 +56,46 @@
         return false;
     }
 
-    NonAppWindowAnimationAdapter(WindowState w,
-            long durationHint, long statusBarTransitionDelay) {
-        mWindow = w;
+    NonAppWindowAnimationAdapter(WindowContainer w, long durationHint,
+            long statusBarTransitionDelay) {
+        mWindowContainer = w;
         mDurationHint = durationHint;
         mStatusBarTransitionDelay = statusBarTransitionDelay;
     }
 
+    static RemoteAnimationTarget[] startNonAppWindowAnimations(WindowManagerService service,
+            DisplayContent displayContent, @WindowManager.TransitionOldType int transit,
+            long durationHint, long statusBarTransitionDelay,
+            ArrayList<NonAppWindowAnimationAdapter> adaptersOut) {
+        final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>();
+        if (transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY
+                || transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER) {
+            startNonAppWindowAnimationsForKeyguardExit(
+                    service, durationHint, statusBarTransitionDelay, targets, adaptersOut);
+        } else if (transit == TRANSIT_OLD_TASK_OPEN || transit == TRANSIT_OLD_TASK_TO_FRONT
+                || transit == TRANSIT_OLD_WALLPAPER_CLOSE) {
+            final boolean shouldAttachNavBarToApp =
+                    displayContent.getDisplayPolicy().shouldAttachNavBarToAppDuringTransition()
+                            && service.getRecentsAnimationController() == null
+                            && displayContent.getFixedRotationAnimationController() == null;
+            if (shouldAttachNavBarToApp) {
+                startNavigationBarWindowAnimation(
+                        displayContent, durationHint, statusBarTransitionDelay, targets,
+                        adaptersOut);
+            }
+        }
+        return targets.toArray(new RemoteAnimationTarget[targets.size()]);
+    }
+
     /**
      * Creates and starts remote animations for all the visible non app windows.
      *
      * @return RemoteAnimationTarget[] targets for all the visible non app windows
      */
-    public static RemoteAnimationTarget[] startNonAppWindowAnimationsForKeyguardExit(
-            WindowManagerService service, long durationHint, long statusBarTransitionDelay) {
-        final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>();
+    private static void startNonAppWindowAnimationsForKeyguardExit(WindowManagerService service,
+            long durationHint, long statusBarTransitionDelay,
+            ArrayList<RemoteAnimationTarget> targets,
+            ArrayList<NonAppWindowAnimationAdapter> adaptersOut) {
 
         final WindowManagerPolicy policy = service.mPolicy;
         service.mRoot.forAllWindows(nonAppWindow -> {
@@ -69,12 +103,30 @@
                     && nonAppWindow.wouldBeVisibleIfPolicyIgnored() && !nonAppWindow.isVisible()) {
                 final NonAppWindowAnimationAdapter nonAppAdapter = new NonAppWindowAnimationAdapter(
                         nonAppWindow, durationHint, statusBarTransitionDelay);
+                adaptersOut.add(nonAppAdapter);
                 nonAppWindow.startAnimation(nonAppWindow.getPendingTransaction(),
                         nonAppAdapter, false /* hidden */, ANIMATION_TYPE_WINDOW_ANIMATION);
                 targets.add(nonAppAdapter.createRemoteAnimationTarget());
             }
         }, true /* traverseTopToBottom */);
-        return targets.toArray(new RemoteAnimationTarget[targets.size()]);
+    }
+
+    /**
+     * Creates and starts remote animation for the navigation bar windows.
+     *
+     * @return RemoteAnimationTarget[] targets for all the visible non app windows
+     */
+    private static void startNavigationBarWindowAnimation(DisplayContent displayContent,
+            long durationHint, long statusBarTransitionDelay,
+            ArrayList<RemoteAnimationTarget> targets,
+            ArrayList<NonAppWindowAnimationAdapter> adaptersOut) {
+        final WindowState navWindow = displayContent.getDisplayPolicy().getNavigationBar();
+        final NonAppWindowAnimationAdapter nonAppAdapter = new NonAppWindowAnimationAdapter(
+                navWindow.mToken, durationHint, statusBarTransitionDelay);
+        adaptersOut.add(nonAppAdapter);
+        navWindow.mToken.startAnimation(navWindow.mToken.getPendingTransaction(),
+                nonAppAdapter, false /* hidden */, ANIMATION_TYPE_WINDOW_ANIMATION);
+        targets.add(nonAppAdapter.createRemoteAnimationTarget());
     }
 
     /**
@@ -82,16 +134,39 @@
      */
     RemoteAnimationTarget createRemoteAnimationTarget() {
         mTarget = new RemoteAnimationTarget(-1, -1, getLeash(), false,
-                new Rect(), null, mWindow.getPrefixOrderIndex(), mWindow.getLastSurfacePosition(),
-                mWindow.getBounds(), null, mWindow.getWindowConfiguration(), true, null, null,
-                null);
+                new Rect(), null, mWindowContainer.getPrefixOrderIndex(),
+                mWindowContainer.getLastSurfacePosition(), mWindowContainer.getBounds(), null,
+                mWindowContainer.getWindowConfiguration(), true, null, null, null,
+                mWindowContainer.getWindowType());
         return mTarget;
     }
 
     @Override
     public void startAnimation(SurfaceControl animationLeash, SurfaceControl.Transaction t,
             int type, SurfaceAnimator.OnAnimationFinishedCallback finishCallback) {
+        ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation");
         mCapturedLeash = animationLeash;
+        mCapturedLeashFinishCallback = finishCallback;
+        mLastAnimationType = type;
+    }
+
+    /**
+     * @return the callback to call to clean up when the animation has finished.
+     */
+    SurfaceAnimator.OnAnimationFinishedCallback getLeashFinishedCallback() {
+        return mCapturedLeashFinishCallback;
+    }
+
+    /**
+     * @return the type of animation.
+     */
+    @SurfaceAnimator.AnimationType
+    int getLastAnimationType() {
+        return mLastAnimationType;
+    }
+
+    WindowContainer getWindowContainer() {
+        return mWindowContainer;
     }
 
     @Override
@@ -120,8 +195,8 @@
     @Override
     public void dump(PrintWriter pw, String prefix) {
         pw.print(prefix);
-        pw.print("token=");
-        pw.println(mWindow.mToken);
+        pw.print("windowContainer=");
+        pw.println(mWindowContainer);
         if (mTarget != null) {
             pw.print(prefix);
             pw.println("Target:");
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index 6fc585e..f851e35 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -16,9 +16,6 @@
 
 package com.android.server.wm;
 
-import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
-import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
-
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_REMOTE_ANIMATIONS;
 import static com.android.server.wm.AnimationAdapterProto.REMOTE;
 import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
@@ -41,6 +38,7 @@
 import android.view.SurfaceControl.Transaction;
 import android.view.WindowManager;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.ProtoLogImpl;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.FastPrintWriter;
@@ -60,10 +58,13 @@
     private static final long TIMEOUT_MS = 2000;
 
     private final WindowManagerService mService;
+    private final DisplayContent mDisplayContent;
     private final RemoteAnimationAdapter mRemoteAnimationAdapter;
     private final ArrayList<RemoteAnimationRecord> mPendingAnimations = new ArrayList<>();
     private final ArrayList<WallpaperAnimationAdapter> mPendingWallpaperAnimations =
             new ArrayList<>();
+    @VisibleForTesting
+    final ArrayList<NonAppWindowAnimationAdapter> mPendingNonAppAnimations = new ArrayList<>();
     private final Rect mTmpRect = new Rect();
     private final Handler mHandler;
     private final Runnable mTimeoutRunnable = () -> cancelAnimation("timeoutRunnable");
@@ -72,9 +73,10 @@
     private boolean mCanceled;
     private boolean mLinkedToDeathOfRunner;
 
-    RemoteAnimationController(WindowManagerService service,
+    RemoteAnimationController(WindowManagerService service, DisplayContent displayContent,
             RemoteAnimationAdapter remoteAnimationAdapter, Handler handler) {
         mService = service;
+        mDisplayContent = displayContent;
         mRemoteAnimationAdapter = remoteAnimationAdapter;
         mHandler = handler;
     }
@@ -224,12 +226,12 @@
     private RemoteAnimationTarget[] createNonAppWindowAnimations(
             @WindowManager.TransitionOldType int transit) {
         ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createNonAppWindowAnimations()");
-        return (transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY
-                || transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER)
-                ? NonAppWindowAnimationAdapter.startNonAppWindowAnimationsForKeyguardExit(mService,
-                    mRemoteAnimationAdapter.getDuration(),
-                    mRemoteAnimationAdapter.getStatusBarTransitionDelay())
-                : new RemoteAnimationTarget[0];
+        return NonAppWindowAnimationAdapter.startNonAppWindowAnimations(mService,
+                mDisplayContent,
+                transit,
+                mRemoteAnimationAdapter.getDuration(),
+                mRemoteAnimationAdapter.getStatusBarTransitionDelay(),
+                mPendingNonAppAnimations);
     }
 
     private void onAnimationFinished() {
@@ -267,6 +269,15 @@
                     mPendingWallpaperAnimations.remove(i);
                     ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\twallpaper=%s", adapter.getToken());
                 }
+
+                for (int i = mPendingNonAppAnimations.size() - 1; i >= 0; i--) {
+                    final NonAppWindowAnimationAdapter adapter = mPendingNonAppAnimations.get(i);
+                    adapter.getLeashFinishedCallback().onAnimationFinished(
+                            adapter.getLastAnimationType(), adapter);
+                    mPendingNonAppAnimations.remove(i);
+                    ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tnonApp=%s",
+                            adapter.getWindowContainer());
+                }
             } catch (Exception e) {
                 Slog.e(TAG, "Failed to finish remote animation", e);
                 throw e;
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 2a768e7..857217f 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -273,7 +273,7 @@
     // Whether tasks have moved and we need to rank the tasks before next OOM scoring
     private boolean mTaskLayersChanged = true;
     private int mTmpTaskLayerRank;
-    private final LockedScheduler mRankTaskLayersScheduler;
+    private final RankTaskLayersRunnable mRankTaskLayersRunnable = new RankTaskLayersRunnable();
 
     private boolean mTmpBoolean;
     private RemoteException mTmpRemoteException;
@@ -451,12 +451,6 @@
         mTaskSupervisor = mService.mTaskSupervisor;
         mTaskSupervisor.mRootWindowContainer = this;
         mDisplayOffTokenAcquirer = mService.new SleepTokenAcquirerImpl("Display-off");
-        mRankTaskLayersScheduler = new LockedScheduler(mService) {
-            @Override
-            public void execute() {
-                rankTaskLayersIfNeeded();
-            }
-        };
     }
 
     boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
@@ -1820,11 +1814,11 @@
     }
 
     /**
-     * @return a list of activities which are the top ones in each visible root task. The first
-     * entry will be the focused activity.
+     * @return a list of pairs, containing activities and their task id which are the top ones in
+     * each visible root task. The first entry will be the focused activity.
      */
-    List<IBinder> getTopVisibleActivities() {
-        final ArrayList<IBinder> topActivityTokens = new ArrayList<>();
+    List<Pair<IBinder, Integer>> getTopVisibleActivities() {
+        final ArrayList<Pair<IBinder, Integer>> topVisibleActivities = new ArrayList<>();
         final Task topFocusedRootTask = getTopDisplayFocusedRootTask();
         // Traverse all displays.
         forAllRootTasks(rootTask -> {
@@ -1832,15 +1826,17 @@
             if (rootTask.shouldBeVisible(null /* starting */)) {
                 final ActivityRecord top = rootTask.getTopNonFinishingActivity();
                 if (top != null) {
+                    Pair<IBinder, Integer> visibleActivity = new Pair<>(top.appToken,
+                            top.getTask().mTaskId);
                     if (rootTask == topFocusedRootTask) {
-                        topActivityTokens.add(0, top.appToken);
+                        topVisibleActivities.add(0, visibleActivity);
                     } else {
-                        topActivityTokens.add(top.appToken);
+                        topVisibleActivities.add(visibleActivity);
                     }
                 }
             }
         });
-        return topActivityTokens;
+        return topVisibleActivities;
     }
 
     @Nullable
@@ -2660,16 +2656,18 @@
     }
 
     void invalidateTaskLayers() {
-        mTaskLayersChanged = true;
-        mRankTaskLayersScheduler.scheduleIfNeeded();
+        if (!mTaskLayersChanged) {
+            mTaskLayersChanged = true;
+            mService.mH.post(mRankTaskLayersRunnable);
+        }
     }
 
     /** Generate oom-score-adjustment rank for all tasks in the system based on z-order. */
-    void rankTaskLayersIfNeeded() {
-        if (!mTaskLayersChanged) {
-            return;
+    void rankTaskLayers() {
+        if (mTaskLayersChanged) {
+            mTaskLayersChanged = false;
+            mService.mH.removeCallbacks(mRankTaskLayersRunnable);
         }
-        mTaskLayersChanged = false;
         mTmpTaskLayerRank = 0;
         // Only rank for leaf tasks because the score of activity is based on immediate parent.
         forAllLeafTasks(task -> {
@@ -3669,32 +3667,14 @@
         }
     }
 
-    /**
-     * Helper class to schedule the runnable if it hasn't scheduled on display thread inside window
-     * manager lock.
-     */
-    abstract static class LockedScheduler implements Runnable {
-        private final ActivityTaskManagerService mService;
-        private boolean mScheduled;
-
-        LockedScheduler(ActivityTaskManagerService service) {
-            mService = service;
-        }
-
+    private class RankTaskLayersRunnable implements Runnable {
         @Override
         public void run() {
             synchronized (mService.mGlobalLock) {
-                mScheduled = false;
-                execute();
-            }
-        }
-
-        abstract void execute();
-
-        void scheduleIfNeeded() {
-            if (!mScheduled) {
-                mService.mH.post(this);
-                mScheduled = true;
+                if (mTaskLayersChanged) {
+                    mTaskLayersChanged = false;
+                    rankTaskLayers();
+                }
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 09a8e4f..a4a0866 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3595,7 +3595,7 @@
             return false;
         }
 
-        if (r.occludesParent() || r.hasWallpaper) {
+        if (r.occludesParent()) {
             // Root task isn't translucent if it has at least one fullscreen activity
             // that is visible.
             return true;
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 375b3f4..565804f 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -153,7 +153,9 @@
 //                }
                 try {
                     mTaskOrganizer.removeStartingWindow(task.mTaskId, firstWindowLeash, mainFrame,
-                            prepareAnimation);
+                    /* TODO(183004107) Revert this when jankiness is solved
+                        prepareAnimation); */ false);
+
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Exception sending onStartTaskFinished callback", e);
                 }
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index aadb272..75be444 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 
+import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_CLOSE;
@@ -411,8 +412,9 @@
     private static boolean reportIfNotTop(WindowContainer wc) {
         // Organized tasks need to be reported anyways because Core won't show() their surfaces
         // and we can't rely on onTaskAppeared because it isn't in sync.
+        // Also report wallpaper so it can be handled properly during display change/rotation.
         // TODO(shell-transitions): switch onTaskAppeared usage over to transitions OPEN.
-        return wc.isOrganized();
+        return wc.isOrganized() || isWallpaper(wc);
     }
 
     /** @return the depth of child within ancestor, 0 if child == ancestor, or -1 if not a child. */
@@ -430,7 +432,7 @@
     }
 
     private static boolean isWallpaper(WindowContainer wc) {
-        return wc instanceof WallpaperWindowToken;
+        return wc.asWallpaperToken() != null;
     }
 
     /**
@@ -576,7 +578,8 @@
         final ArrayList<WindowContainer> tmpList = new ArrayList<>();
 
         // Build initial set of top-level participants by removing any participants that are no-ops
-        // or children of other participants or are otherwise invalid.
+        // or children of other participants or are otherwise invalid; however, keep around a list
+        // of participants that should always be reported even if they aren't top.
         for (WindowContainer wc : participants) {
             // Don't include detached windows.
             if (!wc.isAttached()) continue;
@@ -584,7 +587,11 @@
             final ChangeInfo changeInfo = changes.get(wc);
 
             // Reject no-ops
-            if (!changeInfo.hasChanged(wc)) continue;
+            if (!changeInfo.hasChanged(wc)) {
+                ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+                        "  Rejecting as no-op: %s", wc);
+                continue;
+            }
 
             // Search through ancestors to find the top-most participant (if one exists)
             WindowContainer topParent = null;
@@ -651,10 +658,21 @@
 
     /** Gets the leash surface for a window container */
     private static SurfaceControl getLeashSurface(WindowContainer wc) {
+        final DisplayContent asDC = wc.asDisplayContent();
+        if (asDC != null) {
+            // DisplayContent is the "root", so we use the windowing layer instead to avoid
+            // hardware-screen-level surfaces.
+            return asDC.getWindowingLayer();
+        }
         return wc.getSurfaceControl();
     }
 
     private static SurfaceControl getOrigParentSurface(WindowContainer wc) {
+        if (wc.asDisplayContent() != null) {
+            // DisplayContent is the "root", so we reinterpret it's wc as the window layer
+            // making the parent surface the displaycontent's surface.
+            return wc.getSurfaceControl();
+        }
         return wc.getParent().getSurfaceControl();
     }
 
@@ -744,6 +762,7 @@
             change.setEndRelOffset(target.getBounds().left - target.getParent().getBounds().left,
                     target.getBounds().top - target.getParent().getBounds().top);
             change.setFlags(info.getChangeFlags(target));
+            change.setRotation(info.mRotation, target.getWindowConfiguration().getRotation());
             final Task task = target.asTask();
             if (task != null) {
                 final ActivityManager.RunningTaskInfo tinfo = new ActivityManager.RunningTaskInfo();
@@ -773,12 +792,14 @@
         int mWindowingMode;
         final Rect mAbsoluteBounds = new Rect();
         boolean mShowWallpaper;
+        int mRotation = ROTATION_UNDEFINED;
 
         ChangeInfo(@NonNull WindowContainer origState) {
             mVisible = origState.isVisibleRequested();
             mWindowingMode = origState.getWindowingMode();
             mAbsoluteBounds.set(origState.getBounds());
             mShowWallpaper = origState.showWallpaper();
+            mRotation = origState.getWindowConfiguration().getRotation();
         }
 
         @VisibleForTesting
@@ -797,7 +818,8 @@
                     // if mWindowingMode is 0, this container wasn't attached at collect time, so
                     // assume no change in windowing-mode.
                     || (mWindowingMode != 0 && newState.getWindowingMode() != mWindowingMode)
-                    || !newState.getBounds().equals(mAbsoluteBounds);
+                    || !newState.getBounds().equals(mAbsoluteBounds)
+                    || mRotation != newState.getWindowConfiguration().getRotation();
         }
 
         @TransitionInfo.TransitionMode
@@ -826,8 +848,7 @@
                 //                    checks to use requested visibility.
                 flags |= FLAG_TRANSLUCENT;
             }
-            if (wc instanceof ActivityRecord
-                    && wc.asActivityRecord().mUseTransferredAnimation) {
+            if (wc.asActivityRecord() != null && wc.asActivityRecord().mUseTransferredAnimation) {
                 flags |= FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
             }
             if (isWallpaper(wc)) {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index e3679c0..a5843d4 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -29,6 +29,7 @@
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.os.UserHandle.USER_NULL;
 import static android.view.SurfaceControl.Transaction;
+import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM;
@@ -3083,6 +3084,11 @@
         return null;
     }
 
+    /** Cheap way of doing cast and instanceof. */
+    DisplayContent asDisplayContent() {
+        return null;
+    }
+
     /**
      * @return {@code true} if window container is manage by a
      *          {@link android.window.WindowOrganizer}
@@ -3308,4 +3314,11 @@
         mListeners.remove(listener);
         unregisterConfigurationChangeListener(listener);
     }
+
+    /**
+     * Returns the {@link WindowManager.LayoutParams.WindowType}.
+     */
+    @WindowManager.LayoutParams.WindowType int getWindowType() {
+        return INVALID_WINDOW_TYPE;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
index 74337c2..0840441 100644
--- a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
+++ b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
@@ -44,7 +44,7 @@
     static final boolean DEBUG_STARTING_WINDOW_VERBOSE = false;
     static final boolean DEBUG_WALLPAPER = false;
     static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER;
-    static final boolean DEBUG_DRAG = false;
+    static final boolean DEBUG_DRAG = true;
     static final boolean DEBUG_SCREENSHOT = false;
     static final boolean DEBUG_LAYOUT_REPEATS = false;
     static final boolean DEBUG_WINDOW_TRACE = false;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index dce79a0..57394d6 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1600,11 +1600,17 @@
                     ProtoLog.w(WM_ERROR, "Attempted to add window with exiting application token "
                             + ".%s Aborting.", token);
                     return WindowManagerGlobal.ADD_APP_EXITING;
-                } else if (type == TYPE_APPLICATION_STARTING && activity.mStartingWindow != null) {
-                    ProtoLog.w(WM_ERROR,
-                            "Attempted to add starting window to token with already existing"
-                                    + " starting window");
-                    return WindowManagerGlobal.ADD_DUPLICATE_ADD;
+                } else if (type == TYPE_APPLICATION_STARTING) {
+                    if (activity.mStartingWindow != null) {
+                        ProtoLog.w(WM_ERROR, "Attempted to add starting window to "
+                                + "token with already existing starting window");
+                        return WindowManagerGlobal.ADD_DUPLICATE_ADD;
+                    }
+                    if (activity.mStartingData == null) {
+                        ProtoLog.w(WM_ERROR, "Attempted to add starting window to "
+                                + "token but already cleaned");
+                        return WindowManagerGlobal.ADD_DUPLICATE_ADD;
+                    }
                 }
             } else if (rootType == TYPE_INPUT_METHOD) {
                 if (token.windowType != TYPE_INPUT_METHOD) {
@@ -4142,12 +4148,19 @@
                                 .notifyOnActivityRotation(displayContent.mDisplayId);
                     }
 
-                    if (!rotationChanged || forceRelayout) {
-                        displayContent.setLayoutNeeded();
-                        layoutNeeded = true;
-                    }
-                    if (rotationChanged || alwaysSendConfiguration) {
-                        displayContent.sendNewConfiguration();
+                    final boolean pendingRemoteRotation = rotationChanged
+                            && (displayContent.getDisplayRotation().isWaitingForRemoteRotation()
+                            || mAtmService.getTransitionController().isCollecting());
+                    // Even if alwaysSend, we are waiting for a transition or remote to provide
+                    // rotated configuration, so we can't update configuration yet.
+                    if (!pendingRemoteRotation) {
+                        if (!rotationChanged || forceRelayout) {
+                            displayContent.setLayoutNeeded();
+                            layoutNeeded = true;
+                        }
+                        if (rotationChanged || alwaysSendConfiguration) {
+                            displayContent.sendNewConfiguration();
+                        }
                     }
                 }
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index a46a8d5..64a26ec 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.os.Build.IS_USER;
+import static android.view.CrossWindowBlurListeners.CROSS_WINDOW_BLUR_SUPPORTED;
 
 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;
@@ -135,6 +136,8 @@
                     return runGetLetterboxBackgroundColor(pw);
                 case "reset":
                     return runReset(pw);
+                case "disable-blur":
+                    return runSetBlurDisabled(pw);
                 default:
                     return handleDefaultCommands(cmd);
             }
@@ -214,6 +217,33 @@
         return 0;
     }
 
+    private int runSetBlurDisabled(PrintWriter pw) throws RemoteException {
+        String arg = getNextArg();
+        if (arg == null) {
+            pw.println("Blur supported on device: " + CROSS_WINDOW_BLUR_SUPPORTED);
+            pw.println("Blur enabled: " + mInternal.mBlurController.mBlurEnabled);
+            return 0;
+        }
+
+        final boolean disableBlur;
+        switch (arg) {
+            case "true":
+            case "1":
+                disableBlur = true;
+                break;
+            case "false":
+            case "0":
+                disableBlur = false;
+                break;
+            default:
+                getErrPrintWriter().println("Error: expected true, 1, false, 0, but got " + arg);
+                return -1;
+        }
+
+        mInterface.setForceCrossWindowBlurDisabled(disableBlur);
+        return 0;
+    }
+
     private void printInitialDisplayDensity(PrintWriter pw , int displayId) {
         try {
             final int initialDensity = mInterface.getInitialDisplayDensity(displayId);
@@ -725,6 +755,7 @@
         pw.println("    Set display scaling mode.");
         pw.println("  dismiss-keyguard");
         pw.println("    Dismiss the keyguard, prompting user for auth if necessary.");
+        pw.println("  disable-blur [true|1|false|0]");
         pw.println("  user-rotation [-d DISPLAY_ID] [free|lock] [rotation]");
         pw.println("    Print or set user rotation mode and user rotation.");
         pw.println("  dump-visible-window-views");
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 9973664..e3d549b 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -246,6 +246,21 @@
         ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d", syncId);
         mService.deferWindowLayout();
         try {
+            if (transition != null) {
+                // First check if we have a display rotation transition and if so, update it.
+                final DisplayContent dc = DisplayRotation.getDisplayFromTransition(transition);
+                if (dc != null && transition.mChanges.get(dc).mRotation != dc.getRotation()) {
+                    // Go through all tasks and collect them before the rotation
+                    // TODO(shell-transitions): move collect() to onConfigurationChange once
+                    //       wallpaper handling is synchronized.
+                    dc.forAllTasks(task -> {
+                        if (task.isVisible()) transition.collect(task);
+                    });
+                    dc.getInsetsStateController().addProvidersToTransition();
+                    dc.sendNewConfiguration();
+                    effects |= TRANSACT_EFFECTS_LIFECYCLE;
+                }
+            }
             ArraySet<WindowContainer> haveConfigChanges = new ArraySet<>();
             Iterator<Map.Entry<IBinder, WindowContainerTransaction.Change>> entries =
                     t.getChanges().entrySet().iterator();
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index c5e24a9..bac1ab1 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -225,6 +225,7 @@
     private static final int ACTIVITY_STATE_FLAG_IS_STOPPING_FINISHING = 1 << 19;
     private static final int ACTIVITY_STATE_FLAG_IS_WINDOW_VISIBLE = 1 << 20;
     private static final int ACTIVITY_STATE_FLAG_HAS_RESUMED = 1 << 21;
+    private static final int ACTIVITY_STATE_FLAG_HAS_ACTIVITY_IN_VISIBLE_TASK = 1 << 22;
     private static final int ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER = 0x0000ffff;
 
     /**
@@ -479,7 +480,7 @@
     }
 
     void setLastActivityFinishTimeIfNeeded(long finishTime) {
-        if (finishTime <= mLastActivityFinishTime || !hasVisibleActivities()) {
+        if (finishTime <= mLastActivityFinishTime || !hasActivityInVisibleTask()) {
             return;
         }
         mLastActivityFinishTime = finishTime;
@@ -516,7 +517,7 @@
     private boolean areBackgroundActivityStartsAllowed(boolean appSwitchAllowed,
             boolean isCheckingForFgsStart) {
         return mBgLaunchController.areBackgroundActivityStartsAllowed(mPid, mUid, mInfo.packageName,
-                appSwitchAllowed, isCheckingForFgsStart, hasVisibleActivities(),
+                appSwitchAllowed, isCheckingForFgsStart, hasActivityInVisibleTask(),
                 mInstrumentingWithBackgroundActivityStartPrivileges,
                 mAtm.getLastStopAppSwitchesTime(),
                 mLastActivityLaunchTime, mLastActivityFinishTime);
@@ -653,6 +654,10 @@
         return (mActivityStateFlags & ACTIVITY_STATE_FLAG_IS_VISIBLE) != 0;
     }
 
+    boolean hasActivityInVisibleTask() {
+        return (mActivityStateFlags & ACTIVITY_STATE_FLAG_HAS_ACTIVITY_IN_VISIBLE_TASK) != 0;
+    }
+
     @HotPath(caller = HotPath.LRU_UPDATE)
     public boolean hasActivitiesOrRecentTasks() {
         return mHasActivities || mHasRecentTasks;
@@ -996,11 +1001,14 @@
             if (r.isVisible()) {
                 stateFlags |= ACTIVITY_STATE_FLAG_IS_WINDOW_VISIBLE;
             }
+            final Task task = r.getTask();
+            if (task != null && task.mLayerRank != Task.LAYER_RANK_INVISIBLE) {
+                stateFlags |= ACTIVITY_STATE_FLAG_HAS_ACTIVITY_IN_VISIBLE_TASK;
+            }
             if (r.mVisibleRequested) {
                 if (r.isState(RESUMED)) {
                     stateFlags |= ACTIVITY_STATE_FLAG_HAS_RESUMED;
                 }
-                final Task task = r.getTask();
                 if (task != null && minTaskLayer > 0) {
                     final int layer = task.mLayerRank;
                     if (layer >= 0 && minTaskLayer > layer) {
@@ -1048,7 +1056,7 @@
 
     /** Called when the process has some oom related changes and it is going to update oom-adj. */
     private void prepareOomAdjustment() {
-        mAtm.mRootWindowContainer.rankTaskLayersIfNeeded();
+        mAtm.mRootWindowContainer.rankTaskLayers();
         mAtm.mTaskSupervisor.computeProcessActivityStateBatch();
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 2eadcd5..6d88387 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -5892,4 +5892,9 @@
     void setSurfaceTranslationY(int translationY) {
         mSurfaceTranslationY = translationY;
     }
+
+    @Override
+    @WindowManager.LayoutParams.WindowType int getWindowType() {
+        return mAttrs.type;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 8867aa7..5276d9c8 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -764,4 +764,9 @@
             forAllWindows(WindowState::clearFrozenInsetsState, true /* traverseTopToBottom */);
         }
     }
+
+    @Override
+    @WindowManager.LayoutParams.WindowType int getWindowType() {
+        return windowType;
+    }
 }
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index be06d03..3a674c4 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -131,6 +131,7 @@
     jmethodID getDeviceAlias;
     jmethodID getTouchCalibrationForInputDevice;
     jmethodID getContextForDisplay;
+    jmethodID notifyDropWindow;
 } gServiceClassInfo;
 
 static struct {
@@ -335,6 +336,7 @@
     bool checkInjectEventsPermissionNonReentrant(int32_t injectorPid, int32_t injectorUid) override;
     void onPointerDownOutsideFocus(const sp<IBinder>& touchedToken) override;
     void setPointerCapture(bool enabled) override;
+    void notifyDropWindow(const sp<IBinder>& token, float x, float y) override;
 
     /* --- PointerControllerPolicyInterface implementation --- */
 
@@ -905,6 +907,20 @@
     checkAndClearExceptionFromCallback(env, "notifyFocusChanged");
 }
 
+void NativeInputManager::notifyDropWindow(const sp<IBinder>& token, float x, float y) {
+#if DEBUG_INPUT_DISPATCHER_POLICY
+    ALOGD("notifyDropWindow");
+#endif
+    ATRACE_CALL();
+
+    JNIEnv* env = jniEnv();
+    ScopedLocalFrame localFrame(env);
+
+    jobject tokenObj = javaObjectForIBinder(env, token);
+    env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyDropWindow, tokenObj, x, y);
+    checkAndClearExceptionFromCallback(env, "notifyDropWindow");
+}
+
 void NativeInputManager::notifySensorEvent(int32_t deviceId, InputDeviceSensorType sensorType,
                                            InputDeviceSensorAccuracy accuracy, nsecs_t timestamp,
                                            const std::vector<float>& values) {
@@ -2350,6 +2366,8 @@
 
     GET_METHOD_ID(gServiceClassInfo.notifyFocusChanged, clazz,
             "notifyFocusChanged", "(Landroid/os/IBinder;Landroid/os/IBinder;)V");
+    GET_METHOD_ID(gServiceClassInfo.notifyDropWindow, clazz, "notifyDropWindow",
+                  "(Landroid/os/IBinder;FF)V");
 
     GET_METHOD_ID(gServiceClassInfo.notifySensorEvent, clazz, "notifySensorEvent", "(IIIJ[F)V");
 
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java
index 84e6da0..2825eea 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java
@@ -48,6 +48,11 @@
     private static final String BATTERY_THRESHOLD_CHARGING_KEY =
             "battery_threshold_charging";
 
+    // TODO(b/182994391): Replace with more generic solution to override the supervision
+    // component.
+    private static final String USE_TEST_ADMIN_AS_SUPERVISION_COMPONENT_KEY =
+            "use_test_admin_as_supervision_component";
+
     /**
      * The back-off before re-connecting, when a service binding died, due to the owner
      * crashing repeatedly.
@@ -79,6 +84,12 @@
      */
     public final int BATTERY_THRESHOLD_CHARGING;
 
+    /**
+     * Whether to default to considering the current DO/PO as the supervision component
+     * if they are a testOnly admin.
+     */
+    public final boolean USE_TEST_ADMIN_AS_SUPERVISION_COMPONENT;
+
 
     private DevicePolicyConstants(String settings) {
 
@@ -110,6 +121,9 @@
         int batteryThresholdCharging = parser.getInt(
                 BATTERY_THRESHOLD_CHARGING_KEY, 20);
 
+        boolean useTestAdminAsSupervisionComponent = parser.getBoolean(
+                USE_TEST_ADMIN_AS_SUPERVISION_COMPONENT_KEY, false);
+
         // Set minimum: 5 seconds.
         dasDiedServiceReconnectBackoffSec = Math.max(5, dasDiedServiceReconnectBackoffSec);
 
@@ -128,6 +142,7 @@
                 dasDiedServiceStableConnectionThresholdSec;
         BATTERY_THRESHOLD_NOT_CHARGING = batteryThresholdNotCharging;
         BATTERY_THRESHOLD_CHARGING = batteryThresholdCharging;
+        USE_TEST_ADMIN_AS_SUPERVISION_COMPONENT = useTestAdminAsSupervisionComponent;
     }
 
     public static DevicePolicyConstants loadFromString(String settings) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 7075678..283895b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -51,6 +51,7 @@
 import static android.app.admin.DevicePolicyManager.DELEGATION_NETWORK_LOGGING;
 import static android.app.admin.DevicePolicyManager.DELEGATION_PACKAGE_ACCESS;
 import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT;
+import static android.app.admin.DevicePolicyManager.DELEGATION_SECURITY_LOGGING;
 import static android.app.admin.DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER;
 import static android.app.admin.DevicePolicyManager.ID_TYPE_BASE_INFO;
 import static android.app.admin.DevicePolicyManager.ID_TYPE_IMEI;
@@ -101,6 +102,8 @@
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
 import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
+// TODO (b/178655595) import static android.net.ConnectivityManager.USER_PREFERENCE_ENTERPRISE;
+// TODO (b/178655595) import static android.net.ConnectivityManager.USER_PREFERENCE_SYSTEM_DEFAULT;
 import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
 import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
 import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
@@ -428,6 +431,7 @@
         DELEGATION_INSTALL_EXISTING_PACKAGE,
         DELEGATION_KEEP_UNINSTALLED_PACKAGES,
         DELEGATION_NETWORK_LOGGING,
+        DELEGATION_SECURITY_LOGGING,
         DELEGATION_CERT_SELECTION,
     };
 
@@ -438,9 +442,18 @@
                     DELEGATION_NETWORK_LOGGING,
             });
 
+    // Subset of delegations that can only be delegated by Device Owner or Profile Owner of an
+    // organization-owned and managed profile.
+    private static final List<String>
+            DEVICE_OWNER_OR_ORGANIZATION_OWNED_MANAGED_PROFILE_OWNER_DELEGATIONS =
+            Arrays.asList(new String[]{
+                    DELEGATION_SECURITY_LOGGING,
+            });
+
     // Subset of delegations that only one single package within a given user can hold
     private static final List<String> EXCLUSIVE_DELEGATIONS = Arrays.asList(new String[] {
             DELEGATION_NETWORK_LOGGING,
+            DELEGATION_SECURITY_LOGGING,
             DELEGATION_CERT_SELECTION,
     });
 
@@ -3076,6 +3089,13 @@
         updatePermissionPolicyCache(userId);
         updateAdminCanGrantSensorsPermissionCache(userId);
 
+        boolean enableEnterpriseNetworkSlice = true;
+        synchronized (getLockObject()) {
+            ActiveAdmin owner = getDeviceOrProfileOwnerAdminLocked(userId);
+            enableEnterpriseNetworkSlice = owner != null ? owner.mNetworkSlicingEnabled : true;
+        }
+        updateNetworkPreferenceForUser(userId, enableEnterpriseNetworkSlice);
+
         startOwnerService(userId, "start-user");
     }
 
@@ -3091,6 +3111,7 @@
 
     @Override
     void handleStopUser(int userId) {
+        updateNetworkPreferenceForUser(userId, false);
         stopOwnerService(userId, "stop-user");
     }
 
@@ -5482,7 +5503,8 @@
     @Override
     public boolean hasKeyPair(String callerPackage, String alias) {
         final CallerIdentity caller = getCallerIdentity(callerPackage);
-        Preconditions.checkCallAuthorization(canManageCertificates(caller));
+        Preconditions.checkCallAuthorization(canManageCertificates(caller)
+                || isCredentialManagementApp(caller, alias));
 
         return mInjector.binderWithCleanCallingIdentity(() -> {
             try (KeyChainConnection keyChainConnection =
@@ -6013,6 +6035,10 @@
         if (!Collections.disjoint(scopes, DEVICE_OWNER_OR_MANAGED_PROFILE_OWNER_DELEGATIONS)) {
             Preconditions.checkCallAuthorization(isDeviceOwner(caller)
                     || (isProfileOwner(caller) && isManagedProfile(caller.getUserId())));
+        } else if (!Collections.disjoint(
+                scopes, DEVICE_OWNER_OR_ORGANIZATION_OWNED_MANAGED_PROFILE_OWNER_DELEGATIONS)) {
+            Preconditions.checkCallAuthorization(isDeviceOwner(caller)
+                    || isProfileOwnerOfOrganizationOwnedDevice(caller));
         } else {
             Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
         }
@@ -7647,6 +7673,10 @@
             receiverComponent = resolveDelegateReceiver(DELEGATION_NETWORK_LOGGING, action,
                     deviceOwnerUserId);
         }
+        if (action.equals(DeviceAdminReceiver.ACTION_SECURITY_LOGS_AVAILABLE)) {
+            receiverComponent = resolveDelegateReceiver(DELEGATION_SECURITY_LOGGING, action,
+                    deviceOwnerUserId);
+        }
         if (receiverComponent == null) {
             synchronized (getLockObject()) {
                 receiverComponent = mOwners.getDeviceOwnerComponent();
@@ -7663,6 +7693,10 @@
         if (action.equals(DeviceAdminReceiver.ACTION_NETWORK_LOGS_AVAILABLE)) {
             receiverComponent = resolveDelegateReceiver(DELEGATION_NETWORK_LOGGING, action, userId);
         }
+        if (action.equals(DeviceAdminReceiver.ACTION_SECURITY_LOGS_AVAILABLE)) {
+            receiverComponent = resolveDelegateReceiver(
+                DELEGATION_SECURITY_LOGGING, action, userId);
+        }
         if (receiverComponent == null) {
             receiverComponent = getOwnerComponent(userId);
         }
@@ -8799,11 +8833,15 @@
             final ComponentName doComponent = mOwners.getDeviceOwnerComponent();
             final ComponentName poComponent =
                     mOwners.getProfileOwnerComponent(userHandle.getIdentifier());
-            // Return test only admin by default.
-            if (isAdminTestOnlyLocked(doComponent, userHandle.getIdentifier())) {
-                return doComponent;
-            } else if (isAdminTestOnlyLocked(poComponent, userHandle.getIdentifier())) {
-                return poComponent;
+            // Return test only admin if configured to do so.
+            // TODO(b/182994391): Replace with more generic solution to override the supervision
+            // component.
+            if (mConstants.USE_TEST_ADMIN_AS_SUPERVISION_COMPONENT) {
+                if (isAdminTestOnlyLocked(doComponent, userHandle.getIdentifier())) {
+                    return doComponent;
+                } else if (isAdminTestOnlyLocked(poComponent, userHandle.getIdentifier())) {
+                    return poComponent;
+                }
             }
             final String supervisor = mContext.getResources().getString(
                     com.android.internal.R.string.config_defaultSupervisionProfileOwnerComponent);
@@ -11389,21 +11427,22 @@
         if (!mHasFeature) {
             return;
         }
-
         final CallerIdentity caller = getCallerIdentity();
         Preconditions.checkCallAuthorization(isProfileOwner(caller),
                 "Caller is not profile owner; only profile owner may control the network slicing");
-
         synchronized (getLockObject()) {
             final ActiveAdmin requiredAdmin = getProfileOwnerAdminLocked(
                     caller.getUserId());
             if (requiredAdmin != null && requiredAdmin.mNetworkSlicingEnabled != enabled) {
                 requiredAdmin.mNetworkSlicingEnabled = enabled;
                 saveSettingsLocked(caller.getUserId());
-                // TODO(b/178655595) notify CS the change.
-                // TODO(b/178655595) DevicePolicyEventLogger metrics
             }
         }
+        updateNetworkPreferenceForUser(caller.getUserId(), enabled);
+        DevicePolicyEventLogger
+                .createEvent(DevicePolicyEnums.SET_NETWORK_SLICING_ENABLED)
+                .setBoolean(enabled)
+                .write();
     }
 
     @Override
@@ -11413,11 +11452,8 @@
         }
 
         final CallerIdentity caller = getCallerIdentity();
-        Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
-        Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
-                permission.READ_NETWORK_DEVICE_CONFIG) || isProfileOwner(caller),
-                        "Caller is not profile owner and not granted"
-                                + " READ_NETWORK_DEVICE_CONFIG permission");
+        Preconditions.checkCallAuthorization(isProfileOwner(caller),
+                "Caller is not profile owner");
         synchronized (getLockObject()) {
             final ActiveAdmin requiredAdmin = getProfileOwnerAdminLocked(userHandle);
             if (requiredAdmin != null) {
@@ -12123,6 +12159,16 @@
         @Override
         public void onChange(boolean selfChange, Uri uri, int userId) {
             mConstants = loadConstants();
+
+            mInjector.binderWithCleanCallingIdentity(() -> {
+                final Intent intent = new Intent(
+                        DevicePolicyManager.ACTION_DEVICE_POLICY_CONSTANTS_CHANGED);
+                intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+                final List<UserInfo> users = mUserManager.getAliveUsers();
+                for (int i = 0; i < users.size(); i++) {
+                    mContext.sendBroadcastAsUser(intent, UserHandle.of(users.get(i).id));
+                }
+            });
         }
     }
 
@@ -13897,16 +13943,24 @@
     }
 
     @Override
-    public void setSecurityLoggingEnabled(ComponentName admin, boolean enabled) {
+    public void setSecurityLoggingEnabled(ComponentName admin, String packageName,
+            boolean enabled) {
         if (!mHasFeature) {
             return;
         }
-        Objects.requireNonNull(admin);
-        final CallerIdentity caller = getCallerIdentity(admin);
+        final CallerIdentity caller = getCallerIdentity(admin, packageName);
 
         synchronized (getLockObject()) {
-            Preconditions.checkCallAuthorization(isProfileOwnerOfOrganizationOwnedDevice(caller)
-                    || isDeviceOwner(caller));
+            if (admin != null) {
+                Preconditions.checkCallAuthorization(
+                        isProfileOwnerOfOrganizationOwnedDevice(caller)
+                        || isDeviceOwner(caller));
+            } else {
+                // A delegate app passes a null admin component, which is expected
+                Preconditions.checkCallAuthorization(
+                        isCallerDelegate(caller, DELEGATION_SECURITY_LOGGING));
+            }
+
             if (enabled == mInjector.securityLogGetLoggingEnabledProperty()) {
                 return;
             }
@@ -13926,17 +13980,23 @@
     }
 
     @Override
-    public boolean isSecurityLoggingEnabled(ComponentName admin) {
+    public boolean isSecurityLoggingEnabled(ComponentName admin, String packageName) {
         if (!mHasFeature) {
             return false;
         }
 
         synchronized (getLockObject()) {
             if (!isCallerWithSystemUid()) {
-                Objects.requireNonNull(admin);
-                final CallerIdentity caller = getCallerIdentity(admin);
-                Preconditions.checkCallAuthorization(
-                        isProfileOwnerOfOrganizationOwnedDevice(caller) || isDeviceOwner(caller));
+                final CallerIdentity caller = getCallerIdentity(admin, packageName);
+                if (admin != null) {
+                    Preconditions.checkCallAuthorization(
+                            isProfileOwnerOfOrganizationOwnedDevice(caller)
+                            || isDeviceOwner(caller));
+                } else {
+                    // A delegate app passes a null admin component, which is expected
+                    Preconditions.checkCallAuthorization(
+                            isCallerDelegate(caller, DELEGATION_SECURITY_LOGGING));
+                }
             }
             return mInjector.securityLogGetLoggingEnabledProperty();
         }
@@ -13954,15 +14014,23 @@
     }
 
     @Override
-    public ParceledListSlice<SecurityEvent> retrievePreRebootSecurityLogs(ComponentName admin) {
+    public ParceledListSlice<SecurityEvent> retrievePreRebootSecurityLogs(ComponentName admin,
+            String packageName) {
         if (!mHasFeature) {
             return null;
         }
-        Objects.requireNonNull(admin, "ComponentName is null");
 
-        final CallerIdentity caller = getCallerIdentity(admin);
-        Preconditions.checkCallAuthorization(isDeviceOwner(caller)
-                || isProfileOwnerOfOrganizationOwnedDevice(caller));
+        final CallerIdentity caller = getCallerIdentity(admin, packageName);
+        if (admin != null) {
+            Preconditions.checkCallAuthorization(
+                    isProfileOwnerOfOrganizationOwnedDevice(caller)
+                    || isDeviceOwner(caller));
+        } else {
+            // A delegate app passes a null admin component, which is expected
+            Preconditions.checkCallAuthorization(
+                    isCallerDelegate(caller, DELEGATION_SECURITY_LOGGING));
+        }
+
         Preconditions.checkCallAuthorization(isOrganizationOwnedDeviceWithManagedProfile()
                 || areAllUsersAffiliatedWithDeviceLocked());
 
@@ -13992,15 +14060,22 @@
     }
 
     @Override
-    public ParceledListSlice<SecurityEvent> retrieveSecurityLogs(ComponentName admin) {
+    public ParceledListSlice<SecurityEvent> retrieveSecurityLogs(ComponentName admin,
+            String packageName) {
         if (!mHasFeature) {
             return null;
         }
-        Objects.requireNonNull(admin, "ComponentName is null");
 
-        final CallerIdentity caller = getCallerIdentity(admin);
-        Preconditions.checkCallAuthorization(isDeviceOwner(caller)
-                || isProfileOwnerOfOrganizationOwnedDevice(caller));
+        final CallerIdentity caller = getCallerIdentity(admin, packageName);
+        if (admin != null) {
+            Preconditions.checkCallAuthorization(
+                    isProfileOwnerOfOrganizationOwnedDevice(caller)
+                    || isDeviceOwner(caller));
+        } else {
+            // A delegate app passes a null admin component, which is expected
+            Preconditions.checkCallAuthorization(
+                    isCallerDelegate(caller, DELEGATION_SECURITY_LOGGING));
+        }
         Preconditions.checkCallAuthorization(isOrganizationOwnedDeviceWithManagedProfile()
                 || areAllUsersAffiliatedWithDeviceLocked());
 
@@ -16931,6 +17006,20 @@
         }
     }
 
+    private void updateNetworkPreferenceForUser(int userId, boolean enableEnterprise) {
+        if (!isManagedProfile(userId)) {
+            return;
+        }
+        // TODO(b/178655595)
+        // int networkPreference = enable ? ConnectivityManager.USER_PREFERENCE_ENTERPRISE :
+        //        ConnectivityManager.USER_PREFERENCE_SYSTEM_DEFAULT;
+        // mInjector.binderWithCleanCallingIdentity(() ->
+        //         mInjector.getConnectivityManager().setNetworkPreferenceForUser(
+        //                 UserHandle.of(userId),
+        //                 networkPreference,
+        //                 null /* executor */, null /* listener */));
+    }
+
     @Override
     public boolean canAdminGrantSensorsPermissionsForUser(int userId) {
         if (!mHasFeature) {
diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp
index 8f12b2e..63488f9 100644
--- a/services/incremental/BinderIncrementalService.cpp
+++ b/services/incremental/BinderIncrementalService.cpp
@@ -118,9 +118,10 @@
 binder::Status BinderIncrementalService::createStorage(
         const ::std::string& path, const ::android::content::pm::DataLoaderParamsParcel& params,
         int32_t createMode, int32_t* _aidl_return) {
-    *_aidl_return = mImpl.createStorage(path, params,
-                                        android::incremental::IncrementalService::CreateOptions(
-                                                createMode));
+    *_aidl_return =
+            mImpl.createStorage(path, const_cast<content::pm::DataLoaderParamsParcel&&>(params),
+                                android::incremental::IncrementalService::CreateOptions(
+                                        createMode));
     return ok();
 }
 
@@ -144,9 +145,8 @@
         bool* _aidl_return) {
     *_aidl_return =
             mImpl.startLoading(storageId, const_cast<content::pm::DataLoaderParamsParcel&&>(params),
-                               statusListener,
-                               const_cast<StorageHealthCheckParams&&>(healthCheckParams),
-                               healthListener, perUidReadTimeouts);
+                               statusListener, healthCheckParams, healthListener,
+                               perUidReadTimeouts);
     return ok();
 }
 
@@ -255,20 +255,18 @@
 binder::Status BinderIncrementalService::isFileFullyLoaded(int32_t storageId,
                                                            const std::string& path,
                                                            int32_t* _aidl_return) {
-    *_aidl_return = mImpl.isFileFullyLoaded(storageId, path);
+    *_aidl_return = (int)mImpl.isFileFullyLoaded(storageId, path);
     return ok();
 }
 
 binder::Status BinderIncrementalService::isFullyLoaded(int32_t storageId, int32_t* _aidl_return) {
-    *_aidl_return = mImpl.getLoadingProgress(storageId, /*stopOnFirstIncomplete=*/true)
-                            .blocksRemainingOrError();
+    *_aidl_return = (int)mImpl.isMountFullyLoaded(storageId);
     return ok();
 }
 
 binder::Status BinderIncrementalService::getLoadingProgress(int32_t storageId,
                                                             float* _aidl_return) {
-    *_aidl_return =
-            mImpl.getLoadingProgress(storageId, /*stopOnFirstIncomplete=*/false).getProgress();
+    *_aidl_return = mImpl.getLoadingProgress(storageId).getProgress();
     return ok();
 }
 
@@ -281,8 +279,8 @@
 }
 
 static FileId toFileId(const std::vector<uint8_t>& id) {
-    FileId fid;
-    memcpy(&fid, id.data(), id.size());
+    FileId fid = {};
+    memcpy(&fid, id.data(), std::min(sizeof(fid), id.size()));
     return fid;
 }
 
@@ -336,10 +334,8 @@
         int32_t storageId,
         const ::android::os::incremental::StorageHealthCheckParams& healthCheckParams,
         const ::android::sp<IStorageHealthListener>& healthListener, bool* _aidl_return) {
-    *_aidl_return = mImpl.registerStorageHealthListener(storageId,
-                                                        const_cast<StorageHealthCheckParams&&>(
-                                                                healthCheckParams),
-                                                        healthListener);
+    *_aidl_return =
+            mImpl.registerStorageHealthListener(storageId, healthCheckParams, healthListener);
     return ok();
 }
 
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index db70d44..a88f2b4 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -247,14 +247,17 @@
 }
 
 template <class Func>
-static auto makeCleanup(Func&& f) {
+static auto makeCleanup(Func&& f) requires(!std::is_lvalue_reference_v<Func>) {
     auto deleter = [f = std::move(f)](auto) { f(); };
     // &f is a dangling pointer here, but we actually never use it as deleter moves it in.
     return std::unique_ptr<Func, decltype(deleter)>(&f, std::move(deleter));
 }
 
-static std::unique_ptr<DIR, decltype(&::closedir)> openDir(const char* dir) {
-    return {::opendir(dir), ::closedir};
+static auto openDir(const char* dir) {
+    struct DirCloser {
+        void operator()(DIR* d) const noexcept { ::closedir(d); }
+    };
+    return std::unique_ptr<DIR, DirCloser>(::opendir(dir));
 }
 
 static auto openDir(std::string_view dir) {
@@ -390,9 +393,7 @@
             dprintf(fd, "    storages (%d): {\n", int(mnt.storages.size()));
             for (auto&& [storageId, storage] : mnt.storages) {
                 dprintf(fd, "      [%d] -> [%s] (%d %% loaded) \n", storageId, storage.name.c_str(),
-                        (int)(getLoadingProgressFromPath(mnt, storage.name.c_str(),
-                                                         /*stopOnFirstIncomplete=*/false)
-                                      .getProgress() *
+                        (int)(getLoadingProgressFromPath(mnt, storage.name.c_str()).getProgress() *
                               100));
             }
             dprintf(fd, "    }\n");
@@ -425,21 +426,7 @@
         return true;
     }
 
-    // Check all permanent binds.
-    for (auto&& [_, bindPoint] : ifs.bindPoints) {
-        if (bindPoint.kind != BindKind::Permanent) {
-            continue;
-        }
-        const auto progress = getLoadingProgressFromPath(ifs, bindPoint.sourceDir,
-                                                         /*stopOnFirstIncomplete=*/true);
-        if (!progress.isError() && !progress.fullyLoaded()) {
-            LOG(INFO) << "Non system mount: [" << bindPoint.sourceDir
-                      << "], partial progress: " << progress.getProgress() * 100 << "%";
-            return true;
-        }
-    }
-
-    return false;
+    return mIncFs->isEverythingFullyLoaded(ifs.control) == incfs::LoadingState::MissingBlocks;
 }
 
 void IncrementalService::onSystemReady() {
@@ -487,9 +474,9 @@
     }
 }
 
-StorageId IncrementalService::createStorage(
-        std::string_view mountPoint, const content::pm::DataLoaderParamsParcel& dataLoaderParams,
-        CreateOptions options) {
+StorageId IncrementalService::createStorage(std::string_view mountPoint,
+                                            content::pm::DataLoaderParamsParcel dataLoaderParams,
+                                            CreateOptions options) {
     LOG(INFO) << "createStorage: " << mountPoint << " | " << int(options);
     if (!path::isAbsolute(mountPoint)) {
         LOG(ERROR) << "path is not absolute: " << mountPoint;
@@ -576,7 +563,7 @@
             std::make_shared<IncFsMount>(std::move(mountRoot), mountId, std::move(control), *this);
     // Now it's the |ifs|'s responsibility to clean up after itself, and the only cleanup we need
     // is the removal of the |ifs|.
-    firstCleanupOnFailure.release();
+    (void)firstCleanupOnFailure.release();
 
     auto secondCleanup = [this, &l](auto itPtr) {
         if (!l.owns_lock()) {
@@ -597,9 +584,9 @@
         metadata::Mount m;
         m.mutable_storage()->set_id(ifs->mountId);
         m.mutable_loader()->set_type((int)dataLoaderParams.type);
-        m.mutable_loader()->set_package_name(dataLoaderParams.packageName);
-        m.mutable_loader()->set_class_name(dataLoaderParams.className);
-        m.mutable_loader()->set_arguments(dataLoaderParams.arguments);
+        m.mutable_loader()->set_package_name(std::move(dataLoaderParams.packageName));
+        m.mutable_loader()->set_class_name(std::move(dataLoaderParams.className));
+        m.mutable_loader()->set_arguments(std::move(dataLoaderParams.arguments));
         const auto metadata = m.SerializeAsString();
         if (auto err =
                     mIncFs->makeFile(ifs->control,
@@ -622,7 +609,7 @@
     }
 
     // Done here as well, all data structures are in good state.
-    secondCleanupOnFailure.release();
+    (void)secondCleanupOnFailure.release();
 
     mountIt->second = std::move(ifs);
     l.unlock();
@@ -674,14 +661,14 @@
 }
 
 bool IncrementalService::startLoading(StorageId storageId,
-                                      content::pm::DataLoaderParamsParcel&& dataLoaderParams,
-                                      const DataLoaderStatusListener& statusListener,
-                                      StorageHealthCheckParams&& healthCheckParams,
-                                      const StorageHealthListener& healthListener,
-                                      const std::vector<PerUidReadTimeouts>& perUidReadTimeouts) {
+                                      content::pm::DataLoaderParamsParcel dataLoaderParams,
+                                      DataLoaderStatusListener statusListener,
+                                      const StorageHealthCheckParams& healthCheckParams,
+                                      StorageHealthListener healthListener,
+                                      std::vector<PerUidReadTimeouts> perUidReadTimeouts) {
     // Per Uid timeouts.
     if (!perUidReadTimeouts.empty()) {
-        setUidReadTimeouts(storageId, perUidReadTimeouts);
+        setUidReadTimeouts(storageId, std::move(perUidReadTimeouts));
     }
 
     // Re-initialize DataLoader.
@@ -697,8 +684,9 @@
     l.unlock();
 
     // DataLoader.
-    auto dataLoaderStub = prepareDataLoader(*ifs, std::move(dataLoaderParams), &statusListener,
-                                            std::move(healthCheckParams), &healthListener);
+    auto dataLoaderStub =
+            prepareDataLoader(*ifs, std::move(dataLoaderParams), std::move(statusListener),
+                              healthCheckParams, std::move(healthListener));
     CHECK(dataLoaderStub);
 
     if (dataLoaderStub->isSystemDataLoader()) {
@@ -840,7 +828,7 @@
     }
 
     std::lock_guard l(mMountOperationLock);
-    const auto status = mVold->setIncFsMountOptions(control, enableReadLogs);
+    auto status = mVold->setIncFsMountOptions(control, enableReadLogs);
     if (status.isOk()) {
         // Store enabled state.
         ifs.setReadLogsEnabled(enableReadLogs);
@@ -1209,8 +1197,8 @@
     return mIncFs->getMetadata(ifs->control, node);
 }
 
-void IncrementalService::setUidReadTimeouts(
-        StorageId storage, const std::vector<PerUidReadTimeouts>& perUidReadTimeouts) {
+void IncrementalService::setUidReadTimeouts(StorageId storage,
+                                            std::vector<PerUidReadTimeouts>&& perUidReadTimeouts) {
     using microseconds = std::chrono::microseconds;
     using milliseconds = std::chrono::milliseconds;
 
@@ -1257,13 +1245,13 @@
     }
 
     // Still loading?
-    const auto progress = getLoadingProgress(storage, /*stopOnFirstIncomplete=*/true);
-    if (progress.isError()) {
+    const auto state = isMountFullyLoaded(storage);
+    if (int(state) < 0) {
         // Something is wrong, abort.
         return clearUidReadTimeouts(storage);
     }
 
-    if (progress.started() && progress.fullyLoaded()) {
+    if (state == incfs::LoadingState::Full) {
         // Fully loaded, check readLogs collection.
         const auto ifs = getIfs(storage);
         if (!ifs->readLogsEnabled()) {
@@ -1350,7 +1338,7 @@
 
         auto ifs = std::make_shared<IncFsMount>(std::string(expectedRoot), mountId,
                                                 std::move(control), *this);
-        cleanupFiles.release(); // ifs will take care of that now
+        (void)cleanupFiles.release(); // ifs will take care of that now
 
         // Check if marker file present.
         if (checkReadLogsDisabledMarker(root)) {
@@ -1455,7 +1443,7 @@
             }
             mVold->unmountIncFs(std::string(target));
         }
-        cleanupMounts.release(); // ifs now manages everything
+        (void)cleanupMounts.release(); // ifs now manages everything
 
         if (ifs->bindPoints.empty()) {
             LOG(WARNING) << "No valid bind points for mount " << expectedRoot;
@@ -1628,19 +1616,18 @@
 }
 
 IncrementalService::DataLoaderStubPtr IncrementalService::prepareDataLoader(
-        IncFsMount& ifs, DataLoaderParamsParcel&& params,
-        const DataLoaderStatusListener* statusListener,
-        StorageHealthCheckParams&& healthCheckParams, const StorageHealthListener* healthListener) {
+        IncFsMount& ifs, DataLoaderParamsParcel&& params, DataLoaderStatusListener&& statusListener,
+        const StorageHealthCheckParams& healthCheckParams, StorageHealthListener&& healthListener) {
     std::unique_lock l(ifs.lock);
-    prepareDataLoaderLocked(ifs, std::move(params), statusListener, std::move(healthCheckParams),
-                            healthListener);
+    prepareDataLoaderLocked(ifs, std::move(params), std::move(statusListener), healthCheckParams,
+                            std::move(healthListener));
     return ifs.dataLoaderStub;
 }
 
 void IncrementalService::prepareDataLoaderLocked(IncFsMount& ifs, DataLoaderParamsParcel&& params,
-                                                 const DataLoaderStatusListener* statusListener,
-                                                 StorageHealthCheckParams&& healthCheckParams,
-                                                 const StorageHealthListener* healthListener) {
+                                                 DataLoaderStatusListener&& statusListener,
+                                                 const StorageHealthCheckParams& healthCheckParams,
+                                                 StorageHealthListener&& healthListener) {
     if (ifs.dataLoaderStub) {
         LOG(INFO) << "Skipped data loader preparation because it already exists";
         return;
@@ -1658,8 +1645,8 @@
 
     ifs.dataLoaderStub =
             new DataLoaderStub(*this, ifs.mountId, std::move(params), std::move(fsControlParcel),
-                               statusListener, std::move(healthCheckParams), healthListener,
-                               path::join(ifs.root, constants().mount));
+                               std::move(statusListener), healthCheckParams,
+                               std::move(healthListener), path::join(ifs.root, constants().mount));
 }
 
 template <class Duration>
@@ -1980,39 +1967,34 @@
     return 0;
 }
 
-int IncrementalService::isFileFullyLoaded(StorageId storage, std::string_view filePath) const {
+incfs::LoadingState IncrementalService::isFileFullyLoaded(StorageId storage,
+                                                          std::string_view filePath) const {
     std::unique_lock l(mLock);
     const auto ifs = getIfsLocked(storage);
     if (!ifs) {
         LOG(ERROR) << "isFileFullyLoaded failed, invalid storageId: " << storage;
-        return -EINVAL;
+        return incfs::LoadingState(-EINVAL);
     }
     const auto storageInfo = ifs->storages.find(storage);
     if (storageInfo == ifs->storages.end()) {
         LOG(ERROR) << "isFileFullyLoaded failed, no storage: " << storage;
-        return -EINVAL;
+        return incfs::LoadingState(-EINVAL);
     }
     l.unlock();
-    return isFileFullyLoadedFromPath(*ifs, filePath);
+    return mIncFs->isFileFullyLoaded(ifs->control, filePath);
 }
 
-int IncrementalService::isFileFullyLoadedFromPath(const IncFsMount& ifs,
-                                                  std::string_view filePath) const {
-    const auto [filledBlocks, totalBlocks] = mIncFs->countFilledBlocks(ifs.control, filePath);
-    if (filledBlocks < 0) {
-        LOG(ERROR) << "isFileFullyLoadedFromPath failed to get filled blocks count for: "
-                   << filePath << " errno: " << filledBlocks;
-        return filledBlocks;
+incfs::LoadingState IncrementalService::isMountFullyLoaded(StorageId storage) const {
+    const auto ifs = getIfs(storage);
+    if (!ifs) {
+        LOG(ERROR) << "isMountFullyLoaded failed, invalid storageId: " << storage;
+        return incfs::LoadingState(-EINVAL);
     }
-    if (totalBlocks < filledBlocks) {
-        LOG(ERROR) << "isFileFullyLoadedFromPath failed to get total num of blocks";
-        return -EINVAL;
-    }
-    return totalBlocks - filledBlocks;
+    return mIncFs->isEverythingFullyLoaded(ifs->control);
 }
 
 IncrementalService::LoadingProgress IncrementalService::getLoadingProgress(
-        StorageId storage, bool stopOnFirstIncomplete) const {
+        StorageId storage) const {
     std::unique_lock l(mLock);
     const auto ifs = getIfsLocked(storage);
     if (!ifs) {
@@ -2025,12 +2007,11 @@
         return {-EINVAL, -EINVAL};
     }
     l.unlock();
-    return getLoadingProgressFromPath(*ifs, storageInfo->second.name, stopOnFirstIncomplete);
+    return getLoadingProgressFromPath(*ifs, storageInfo->second.name);
 }
 
 IncrementalService::LoadingProgress IncrementalService::getLoadingProgressFromPath(
-        const IncFsMount& ifs, std::string_view storagePath,
-        const bool stopOnFirstIncomplete) const {
+        const IncFsMount& ifs, std::string_view storagePath) const {
     ssize_t totalBlocks = 0, filledBlocks = 0, error = 0;
     mFs->listFilesRecursive(storagePath, [&, this](auto filePath) {
         const auto [filledBlocksCount, totalBlocksCount] =
@@ -2043,24 +2024,21 @@
         }
         if (filledBlocksCount < 0) {
             LOG(ERROR) << "getLoadingProgress failed to get filled blocks count for: " << filePath
-                       << " errno: " << filledBlocksCount;
+                       << ", errno: " << filledBlocksCount;
             error = filledBlocksCount;
             return false;
         }
         totalBlocks += totalBlocksCount;
         filledBlocks += filledBlocksCount;
-        if (stopOnFirstIncomplete && filledBlocks < totalBlocks) {
-            return false;
-        }
         return true;
     });
 
     return error ? LoadingProgress{error, error} : LoadingProgress{filledBlocks, totalBlocks};
 }
 
-bool IncrementalService::updateLoadingProgress(
-        StorageId storage, const StorageLoadingProgressListener& progressListener) {
-    const auto progress = getLoadingProgress(storage, /*stopOnFirstIncomplete=*/false);
+bool IncrementalService::updateLoadingProgress(StorageId storage,
+                                               StorageLoadingProgressListener&& progressListener) {
+    const auto progress = getLoadingProgress(storage);
     if (progress.isError()) {
         // Failed to get progress from incfs, abort.
         return false;
@@ -2072,15 +2050,15 @@
     }
     addTimedJob(*mProgressUpdateJobQueue, storage,
                 Constants::progressUpdateInterval /* repeat after 1s */,
-                [storage, progressListener, this]() {
-                    updateLoadingProgress(storage, progressListener);
+                [storage, progressListener = std::move(progressListener), this]() mutable {
+                    updateLoadingProgress(storage, std::move(progressListener));
                 });
     return true;
 }
 
 bool IncrementalService::registerLoadingProgressListener(
-        StorageId storage, const StorageLoadingProgressListener& progressListener) {
-    return updateLoadingProgress(storage, progressListener);
+        StorageId storage, StorageLoadingProgressListener progressListener) {
+    return updateLoadingProgress(storage, std::move(progressListener));
 }
 
 bool IncrementalService::unregisterLoadingProgressListener(StorageId storage) {
@@ -2088,8 +2066,8 @@
 }
 
 bool IncrementalService::registerStorageHealthListener(
-        StorageId storage, StorageHealthCheckParams&& healthCheckParams,
-        const StorageHealthListener& healthListener) {
+        StorageId storage, const StorageHealthCheckParams& healthCheckParams,
+        StorageHealthListener healthListener) {
     DataLoaderStubPtr dataLoaderStub;
     {
         std::unique_lock l(mLock);
@@ -2102,14 +2080,12 @@
             return false;
         }
     }
-    dataLoaderStub->setHealthListener(std::move(healthCheckParams), &healthListener);
+    dataLoaderStub->setHealthListener(healthCheckParams, std::move(healthListener));
     return true;
 }
 
 void IncrementalService::unregisterStorageHealthListener(StorageId storage) {
-    StorageHealthCheckParams invalidCheckParams;
-    invalidCheckParams.blockedTimeoutMs = -1;
-    registerStorageHealthListener(storage, std::move(invalidCheckParams), {});
+    registerStorageHealthListener(storage, {}, {});
 }
 
 bool IncrementalService::perfLoggingEnabled() {
@@ -2234,26 +2210,23 @@
     return ifs->dataLoaderStub->elapsedMsSinceOldestPendingRead();
 }
 
-IncrementalService::DataLoaderStub::DataLoaderStub(IncrementalService& service, MountId id,
-                                                   DataLoaderParamsParcel&& params,
-                                                   FileSystemControlParcel&& control,
-                                                   const DataLoaderStatusListener* statusListener,
-                                                   StorageHealthCheckParams&& healthCheckParams,
-                                                   const StorageHealthListener* healthListener,
-                                                   std::string&& healthPath)
+IncrementalService::DataLoaderStub::DataLoaderStub(
+        IncrementalService& service, MountId id, DataLoaderParamsParcel&& params,
+        FileSystemControlParcel&& control, DataLoaderStatusListener&& statusListener,
+        const StorageHealthCheckParams& healthCheckParams, StorageHealthListener&& healthListener,
+        std::string&& healthPath)
       : mService(service),
         mId(id),
         mParams(std::move(params)),
         mControl(std::move(control)),
-        mStatusListener(statusListener ? *statusListener : DataLoaderStatusListener()),
-        mHealthListener(healthListener ? *healthListener : StorageHealthListener()),
+        mStatusListener(std::move(statusListener)),
+        mHealthListener(std::move(healthListener)),
         mHealthPath(std::move(healthPath)),
-        mHealthCheckParams(std::move(healthCheckParams)) {
-    if (mHealthListener) {
-        if (!isHealthParamsValid()) {
-            mHealthListener = {};
-        }
-    } else {
+        mHealthCheckParams(healthCheckParams) {
+    if (mHealthListener && !isHealthParamsValid()) {
+        mHealthListener = {};
+    }
+    if (!mHealthListener) {
         // Disable advanced health check statuses.
         mHealthCheckParams.blockedTimeoutMs = -1;
     }
@@ -2597,7 +2570,7 @@
             mHealthCheckParams.blockedTimeoutMs < mHealthCheckParams.unhealthyTimeoutMs;
 }
 
-void IncrementalService::DataLoaderStub::onHealthStatus(StorageHealthListener healthListener,
+void IncrementalService::DataLoaderStub::onHealthStatus(const StorageHealthListener& healthListener,
                                                         int healthStatus) {
     LOG(DEBUG) << id() << ": healthStatus: " << healthStatus;
     if (healthListener) {
@@ -2822,14 +2795,12 @@
 }
 
 void IncrementalService::DataLoaderStub::setHealthListener(
-        StorageHealthCheckParams&& healthCheckParams, const StorageHealthListener* healthListener) {
+        const StorageHealthCheckParams& healthCheckParams, StorageHealthListener&& healthListener) {
     std::lock_guard lock(mMutex);
-    mHealthCheckParams = std::move(healthCheckParams);
-    if (healthListener == nullptr) {
-        // reset listener and params
-        mHealthListener = {};
-    } else {
-        mHealthListener = *healthListener;
+    mHealthCheckParams = healthCheckParams;
+    mHealthListener = std::move(healthListener);
+    if (!mHealthListener) {
+        mHealthCheckParams.blockedTimeoutMs = -1;
     }
 }
 
@@ -2865,7 +2836,7 @@
     dprintf(fd, "        lastPendingReads: \n");
     const auto control = mService.mIncFs->openMount(mHealthPath);
     for (auto&& pendingRead : mLastPendingReads) {
-        dprintf(fd, "          fileId: %s\n", mService.mIncFs->toString(pendingRead.id).c_str());
+        dprintf(fd, "          fileId: %s\n", IncFsWrapper::toString(pendingRead.id).c_str());
         const auto metadata = mService.mIncFs->getMetadata(control, pendingRead.id);
         dprintf(fd, "          metadataHex: %s\n", toHexString(metadata).c_str());
         dprintf(fd, "          blockIndex: %d\n", pendingRead.block);
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index bc441c7..4a5db06 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -136,17 +136,17 @@
     void onSystemReady();
 
     StorageId createStorage(std::string_view mountPoint,
-                            const content::pm::DataLoaderParamsParcel& dataLoaderParams,
+                            content::pm::DataLoaderParamsParcel dataLoaderParams,
                             CreateOptions options);
     StorageId createLinkedStorage(std::string_view mountPoint, StorageId linkedStorage,
                                   CreateOptions options = CreateOptions::Default);
     StorageId openStorage(std::string_view path);
 
-    bool startLoading(StorageId storage, content::pm::DataLoaderParamsParcel&& dataLoaderParams,
-                      const DataLoaderStatusListener& statusListener,
-                      StorageHealthCheckParams&& healthCheckParams,
-                      const StorageHealthListener& healthListener,
-                      const std::vector<PerUidReadTimeouts>& perUidReadTimeouts);
+    bool startLoading(StorageId storage, content::pm::DataLoaderParamsParcel dataLoaderParams,
+                      DataLoaderStatusListener statusListener,
+                      const StorageHealthCheckParams& healthCheckParams,
+                      StorageHealthListener healthListener,
+                      std::vector<PerUidReadTimeouts> perUidReadTimeouts);
 
     int bind(StorageId storage, std::string_view source, std::string_view target, BindKind kind);
     int unbind(StorageId storage, std::string_view target);
@@ -164,16 +164,17 @@
              std::string_view newPath);
     int unlink(StorageId storage, std::string_view path);
 
-    int isFileFullyLoaded(StorageId storage, std::string_view filePath) const;
+    incfs::LoadingState isFileFullyLoaded(StorageId storage, std::string_view filePath) const;
+    incfs::LoadingState isMountFullyLoaded(StorageId storage) const;
 
-    LoadingProgress getLoadingProgress(StorageId storage, bool stopOnFirstIncomplete) const;
+    LoadingProgress getLoadingProgress(StorageId storage) const;
 
     bool registerLoadingProgressListener(StorageId storage,
-                                         const StorageLoadingProgressListener& progressListener);
+                                         StorageLoadingProgressListener progressListener);
     bool unregisterLoadingProgressListener(StorageId storage);
     bool registerStorageHealthListener(StorageId storage,
-                                       StorageHealthCheckParams&& healthCheckParams,
-                                       const StorageHealthListener& healthListener);
+                                       const StorageHealthCheckParams& healthCheckParams,
+                                       StorageHealthListener healthListener);
     void unregisterStorageHealthListener(StorageId storage);
     RawMetadata getMetadata(StorageId storage, std::string_view path) const;
     RawMetadata getMetadata(StorageId storage, FileId node) const;
@@ -215,9 +216,9 @@
         DataLoaderStub(IncrementalService& service, MountId id,
                        content::pm::DataLoaderParamsParcel&& params,
                        content::pm::FileSystemControlParcel&& control,
-                       const DataLoaderStatusListener* statusListener,
-                       StorageHealthCheckParams&& healthCheckParams,
-                       const StorageHealthListener* healthListener, std::string&& healthPath);
+                       DataLoaderStatusListener&& statusListener,
+                       const StorageHealthCheckParams& healthCheckParams,
+                       StorageHealthListener&& healthListener, std::string&& healthPath);
         ~DataLoaderStub();
         // Cleans up the internal state and invalidates DataLoaderStub. Any subsequent calls will
         // result in an error.
@@ -232,8 +233,8 @@
         MountId id() const { return mId.load(std::memory_order_relaxed); }
         const content::pm::DataLoaderParamsParcel& params() const { return mParams; }
         bool isSystemDataLoader() const;
-        void setHealthListener(StorageHealthCheckParams&& healthCheckParams,
-                               const StorageHealthListener* healthListener);
+        void setHealthListener(const StorageHealthCheckParams& healthCheckParams,
+                               StorageHealthListener&& healthListener);
         long elapsedMsSinceOldestPendingRead();
 
     private:
@@ -254,7 +255,7 @@
 
         bool fsmStep();
 
-        void onHealthStatus(StorageHealthListener healthListener, int healthStatus);
+        void onHealthStatus(const StorageHealthListener& healthListener, int healthStatus);
         void updateHealthStatus(bool baseline = false);
 
         bool isValid() const { return id() != kInvalidStorageId; }
@@ -363,7 +364,7 @@
     static bool perfLoggingEnabled();
 
     void setUidReadTimeouts(StorageId storage,
-                            const std::vector<PerUidReadTimeouts>& perUidReadTimeouts);
+                            std::vector<PerUidReadTimeouts>&& perUidReadTimeouts);
     void clearUidReadTimeouts(StorageId storage);
     void updateUidReadTimeouts(StorageId storage, Clock::time_point timeLimit);
 
@@ -388,13 +389,13 @@
 
     DataLoaderStubPtr prepareDataLoader(IncFsMount& ifs,
                                         content::pm::DataLoaderParamsParcel&& params,
-                                        const DataLoaderStatusListener* statusListener = nullptr,
-                                        StorageHealthCheckParams&& healthCheckParams = {},
-                                        const StorageHealthListener* healthListener = nullptr);
+                                        DataLoaderStatusListener&& statusListener = {},
+                                        const StorageHealthCheckParams& healthCheckParams = {},
+                                        StorageHealthListener&& healthListener = {});
     void prepareDataLoaderLocked(IncFsMount& ifs, content::pm::DataLoaderParamsParcel&& params,
-                                 const DataLoaderStatusListener* statusListener = nullptr,
-                                 StorageHealthCheckParams&& healthCheckParams = {},
-                                 const StorageHealthListener* healthListener = nullptr);
+                                 DataLoaderStatusListener&& statusListener = {},
+                                 const StorageHealthCheckParams& healthCheckParams = {},
+                                 StorageHealthListener&& healthListener = {});
 
     BindPathMap::const_iterator findStorageLocked(std::string_view path) const;
     StorageId findStorageId(std::string_view path) const;
@@ -412,9 +413,7 @@
     int setStorageParams(IncFsMount& ifs, StorageId storageId, bool enableReadLogs);
     binder::Status applyStorageParams(IncFsMount& ifs, bool enableReadLogs);
 
-    int isFileFullyLoadedFromPath(const IncFsMount& ifs, std::string_view filePath) const;
-    LoadingProgress getLoadingProgressFromPath(const IncFsMount& ifs, std::string_view path,
-                                               bool stopOnFirstIncomplete) const;
+    LoadingProgress getLoadingProgressFromPath(const IncFsMount& ifs, std::string_view path) const;
 
     int setFileContent(const IfsMountPtr& ifs, const incfs::FileId& fileId,
                        std::string_view debugFilePath, std::span<const uint8_t> data) const;
@@ -433,7 +432,7 @@
     bool addTimedJob(TimedQueueWrapper& timedQueue, MountId id, Milliseconds after, Job what);
     bool removeTimedJobs(TimedQueueWrapper& timedQueue, MountId id);
     bool updateLoadingProgress(int32_t storageId,
-                               const StorageLoadingProgressListener& progressListener);
+                               StorageLoadingProgressListener&& progressListener);
     long getMillsSinceOldestPendingRead(StorageId storage);
 
 private:
@@ -455,7 +454,7 @@
     BindPathMap mBindsByPath;
 
     std::mutex mCallbacksLock;
-    std::map<std::string, sp<AppOpsListener>> mCallbackRegistered;
+    std::unordered_map<std::string, sp<AppOpsListener>> mCallbackRegistered;
 
     std::atomic_bool mSystemReady = false;
     StorageId mNextId = 0;
diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp
index 2a06122..7e85f9d 100644
--- a/services/incremental/ServiceWrappers.cpp
+++ b/services/incremental/ServiceWrappers.cpp
@@ -134,6 +134,10 @@
     } mLooper;
 };
 
+std::string IncFsWrapper::toString(FileId fileId) {
+    return incfs::toString(fileId);
+}
+
 class RealIncFs final : public IncFsWrapper {
 public:
     RealIncFs() = default;
@@ -173,9 +177,16 @@
     FileId getFileId(const Control& control, std::string_view path) const final {
         return incfs::getFileId(control, path);
     }
-    std::string toString(FileId fileId) const final { return incfs::toString(fileId); }
     std::pair<IncFsBlockIndex, IncFsBlockIndex> countFilledBlocks(
             const Control& control, std::string_view path) const final {
+        if (incfs::features() & Features::v2) {
+            const auto counts = incfs::getBlockCount(control, path);
+            if (!counts) {
+                return {-errno, -errno};
+            }
+            return {counts->filledDataBlocks + counts->filledHashBlocks,
+                    counts->totalDataBlocks + counts->totalHashBlocks};
+        }
         const auto fileId = incfs::getFileId(control, path);
         const auto fd = incfs::openForSpecialOps(control, fileId);
         int res = fd.get();
@@ -197,6 +208,13 @@
         }
         return {filledBlockCount, totalBlocksCount};
     }
+    incfs::LoadingState isFileFullyLoaded(const Control& control,
+                                          std::string_view path) const final {
+        return incfs::isFullyLoaded(control, path);
+    }
+    incfs::LoadingState isEverythingFullyLoaded(const Control& control) const final {
+        return incfs::isEverythingFullyLoaded(control);
+    }
     ErrorCode link(const Control& control, std::string_view from, std::string_view to) const final {
         return incfs::link(control, from, to);
     }
diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h
index 231b76f..a787db5 100644
--- a/services/incremental/ServiceWrappers.h
+++ b/services/incremental/ServiceWrappers.h
@@ -84,6 +84,8 @@
             void(std::string_view root, std::string_view backingDir,
                  std::span<std::pair<std::string_view, std::string_view>> binds)>;
 
+    static std::string toString(FileId fileId);
+
     virtual ~IncFsWrapper() = default;
     virtual Features features() const = 0;
     virtual void listExistingMounts(const ExistingMountCallback& cb) const = 0;
@@ -99,9 +101,11 @@
     virtual incfs::RawMetadata getMetadata(const Control& control, FileId fileid) const = 0;
     virtual incfs::RawMetadata getMetadata(const Control& control, std::string_view path) const = 0;
     virtual FileId getFileId(const Control& control, std::string_view path) const = 0;
-    virtual std::string toString(FileId fileId) const = 0;
     virtual std::pair<IncFsBlockIndex, IncFsBlockIndex> countFilledBlocks(
             const Control& control, std::string_view path) const = 0;
+    virtual incfs::LoadingState isFileFullyLoaded(const Control& control,
+                                                  std::string_view path) const = 0;
+    virtual incfs::LoadingState isEverythingFullyLoaded(const Control& control) const = 0;
     virtual ErrorCode link(const Control& control, std::string_view from,
                            std::string_view to) const = 0;
     virtual ErrorCode unlink(const Control& control, std::string_view path) const = 0;
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 45b796b..54bc95d 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -362,10 +362,12 @@
     MOCK_CONST_METHOD2(getMetadata, RawMetadata(const Control& control, FileId fileid));
     MOCK_CONST_METHOD2(getMetadata, RawMetadata(const Control& control, std::string_view path));
     MOCK_CONST_METHOD2(getFileId, FileId(const Control& control, std::string_view path));
-    MOCK_CONST_METHOD1(toString, std::string(FileId fileId));
     MOCK_CONST_METHOD2(countFilledBlocks,
                        std::pair<IncFsBlockIndex, IncFsBlockIndex>(const Control& control,
                                                                    std::string_view path));
+    MOCK_CONST_METHOD2(isFileFullyLoaded,
+                       incfs::LoadingState(const Control& control, std::string_view path));
+    MOCK_CONST_METHOD1(isEverythingFullyLoaded, incfs::LoadingState(const Control& control));
     MOCK_CONST_METHOD3(link,
                        ErrorCode(const Control& control, std::string_view from,
                                  std::string_view to));
@@ -1563,51 +1565,37 @@
     ASSERT_EQ(res, 0);
 }
 
-TEST_F(IncrementalServiceTest, testIsFileFullyLoadedFailsWithNoFile) {
-    mIncFs->countFilledBlocksFails();
-    mFs->hasNoFile();
-
+TEST_F(IncrementalServiceTest, testIsFileFullyLoadedNoData) {
     TemporaryDir tempDir;
     int storageId =
             mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
                                                IncrementalService::CreateOptions::CreateNew);
-    ASSERT_EQ(-1, mIncrementalService->isFileFullyLoaded(storageId, "base.apk"));
+    EXPECT_CALL(*mIncFs, isFileFullyLoaded(_, _))
+            .Times(1)
+            .WillOnce(Return(incfs::LoadingState::MissingBlocks));
+    ASSERT_GT((int)mIncrementalService->isFileFullyLoaded(storageId, "base.apk"), 0);
 }
 
-TEST_F(IncrementalServiceTest, testIsFileFullyLoadedFailsWithFailedRanges) {
-    mIncFs->countFilledBlocksFails();
-    mFs->hasFiles();
-
+TEST_F(IncrementalServiceTest, testIsFileFullyLoadedError) {
     TemporaryDir tempDir;
     int storageId =
             mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
                                                IncrementalService::CreateOptions::CreateNew);
-    EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(1);
-    ASSERT_EQ(-1, mIncrementalService->isFileFullyLoaded(storageId, "base.apk"));
-}
-
-TEST_F(IncrementalServiceTest, testIsFileFullyLoadedSuccessWithEmptyRanges) {
-    mIncFs->countFilledBlocksEmpty();
-    mFs->hasFiles();
-
-    TemporaryDir tempDir;
-    int storageId =
-            mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
-                                               IncrementalService::CreateOptions::CreateNew);
-    EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(1);
-    ASSERT_EQ(0, mIncrementalService->isFileFullyLoaded(storageId, "base.apk"));
+    EXPECT_CALL(*mIncFs, isFileFullyLoaded(_, _))
+            .Times(1)
+            .WillOnce(Return(incfs::LoadingState(-1)));
+    ASSERT_LT((int)mIncrementalService->isFileFullyLoaded(storageId, "base.apk"), 0);
 }
 
 TEST_F(IncrementalServiceTest, testIsFileFullyLoadedSuccess) {
-    mIncFs->countFilledBlocksFullyLoaded();
-    mFs->hasFiles();
-
     TemporaryDir tempDir;
     int storageId =
             mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
                                                IncrementalService::CreateOptions::CreateNew);
-    EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(1);
-    ASSERT_EQ(0, mIncrementalService->isFileFullyLoaded(storageId, "base.apk"));
+    EXPECT_CALL(*mIncFs, isFileFullyLoaded(_, _))
+            .Times(1)
+            .WillOnce(Return(incfs::LoadingState::Full));
+    ASSERT_EQ(0, (int)mIncrementalService->isFileFullyLoaded(storageId, "base.apk"));
 }
 
 TEST_F(IncrementalServiceTest, testGetLoadingProgressSuccessWithNoFile) {
@@ -1618,9 +1606,7 @@
     int storageId =
             mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
                                                IncrementalService::CreateOptions::CreateNew);
-    ASSERT_EQ(1,
-              mIncrementalService->getLoadingProgress(storageId, /*stopOnFirstIncomplete=*/false)
-                      .getProgress());
+    ASSERT_EQ(1, mIncrementalService->getLoadingProgress(storageId).getProgress());
 }
 
 TEST_F(IncrementalServiceTest, testGetLoadingProgressFailsWithFailedRanges) {
@@ -1632,9 +1618,7 @@
             mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
                                                IncrementalService::CreateOptions::CreateNew);
     EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(1);
-    ASSERT_EQ(-1,
-              mIncrementalService->getLoadingProgress(storageId, /*stopOnFirstIncomplete=*/false)
-                      .getProgress());
+    ASSERT_EQ(-1, mIncrementalService->getLoadingProgress(storageId).getProgress());
 }
 
 TEST_F(IncrementalServiceTest, testGetLoadingProgressSuccessWithEmptyRanges) {
@@ -1646,9 +1630,7 @@
             mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
                                                IncrementalService::CreateOptions::CreateNew);
     EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(3);
-    ASSERT_EQ(1,
-              mIncrementalService->getLoadingProgress(storageId, /*stopOnFirstIncomplete=*/false)
-                      .getProgress());
+    ASSERT_EQ(1, mIncrementalService->getLoadingProgress(storageId).getProgress());
 }
 
 TEST_F(IncrementalServiceTest, testGetLoadingProgressSuccess) {
@@ -1660,9 +1642,7 @@
             mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
                                                IncrementalService::CreateOptions::CreateNew);
     EXPECT_CALL(*mIncFs, countFilledBlocks(_, _)).Times(3);
-    ASSERT_EQ(0.5,
-              mIncrementalService->getLoadingProgress(storageId, /*stopOnFirstIncomplete=*/false)
-                      .getProgress());
+    ASSERT_EQ(0.5, mIncrementalService->getLoadingProgress(storageId).getProgress());
 }
 
 TEST_F(IncrementalServiceTest, testRegisterLoadingProgressListenerSuccess) {
@@ -1845,8 +1825,12 @@
             .WillOnce(Invoke(&checkPerUidTimeoutsEmpty));
     EXPECT_CALL(*mTimedQueue, addJob(_, _, _)).Times(3);
 
-    // Empty storage.
-    mIncFs->countFilledBlocksEmpty();
+    // Loading storage.
+    EXPECT_CALL(*mIncFs, isEverythingFullyLoaded(_))
+            .WillOnce(Return(incfs::LoadingState::MissingBlocks))
+            .WillOnce(Return(incfs::LoadingState::MissingBlocks))
+            .WillOnce(Return(incfs::LoadingState::Full))
+            .WillOnce(Return(incfs::LoadingState::Full));
 
     // Mark DataLoader as 'system' so that readlogs don't pollute the timed queue.
     mDataLoaderParcel.packageName = "android";
@@ -1867,22 +1851,18 @@
         const auto timedCallback = mTimedQueue->mWhat;
         mTimedQueue->clearJob(storageId);
 
-        // Still loading.
-        mIncFs->countFilledBlocksSuccess();
-
         // Call it again.
         timedCallback();
     }
 
     {
-        // Still present -> 0.5 progress.
+        // Still present -> some progress.
         ASSERT_EQ(storageId, mTimedQueue->mId);
         ASSERT_GE(mTimedQueue->mAfter, std::chrono::seconds(1));
         const auto timedCallback = mTimedQueue->mWhat;
         mTimedQueue->clearJob(storageId);
 
         // Fully loaded but readlogs collection enabled.
-        mIncFs->countFilledBlocksFullyLoaded();
         ASSERT_GE(mDataLoader->setStorageParams(true), 0);
 
         // Call it again.
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 7e4bc1e..f73af53 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
@@ -52,6 +52,7 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import android.Manifest;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.AlarmManager;
@@ -66,7 +67,10 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.ServiceInfo;
 import android.os.BatteryManager;
@@ -75,6 +79,7 @@
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.platform.test.annotations.LargeTest;
 import android.provider.DeviceConfig;
 import android.util.SparseBooleanArray;
 
@@ -141,6 +146,8 @@
     @Mock
     private JobSchedulerService mJobSchedulerService;
     @Mock
+    private PackageManager mPackageManager;
+    @Mock
     private PackageManagerInternal mPackageManagerInternal;
     @Mock
     private PowerAllowlistInternal mPowerAllowlistInternal;
@@ -200,6 +207,8 @@
                         -> mDeviceConfigPropertiesBuilder.build())
                 .when(() -> DeviceConfig.getProperties(
                         eq(DeviceConfig.NAMESPACE_JOB_SCHEDULER), ArgumentMatchers.<String>any()));
+        // Used in QuotaController.onSystemServicesReady
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
 
         // Freeze the clocks at 24 hours after this moment in time. Several tests create sessions
         // in the past, and QuotaController sometimes floors values at 0, so if the test time
@@ -286,14 +295,20 @@
             doReturn(procState).when(mActivityMangerInternal).getUidProcessState(uid);
             SparseBooleanArray foregroundUids = mQuotaController.getForegroundUids();
             spyOn(foregroundUids);
+            final boolean contained = foregroundUids.get(uid);
             mUidObserver.onUidStateChanged(uid, procState, 0,
                     ActivityManager.PROCESS_CAPABILITY_NONE);
             if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
-                verify(foregroundUids, timeout(2 * SECOND_IN_MILLIS).times(1))
-                        .put(eq(uid), eq(true));
+                if (!contained) {
+                    verify(foregroundUids, timeout(2 * SECOND_IN_MILLIS).times(1))
+                            .put(eq(uid), eq(true));
+                }
                 assertTrue(foregroundUids.get(uid));
             } else {
-                verify(foregroundUids, timeout(2 * SECOND_IN_MILLIS).times(1)).delete(eq(uid));
+                if (contained) {
+                    verify(foregroundUids, timeout(2 * SECOND_IN_MILLIS).times(1))
+                            .delete(eq(uid));
+                }
                 assertFalse(foregroundUids.get(uid));
             }
             waitForNonDelayedMessagesProcessed();
@@ -1993,7 +2008,7 @@
 
         setProcessState(ActivityManager.PROCESS_STATE_RECEIVER);
         final long gracePeriodMs = 15 * SECOND_IN_MILLIS;
-        setDeviceConfigLong(QcConstants.KEY_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS, gracePeriodMs);
+        setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS, gracePeriodMs);
         Handler handler = mQuotaController.getHandler();
         spyOn(handler);
 
@@ -2017,6 +2032,52 @@
         }
     }
 
+    /**
+     * Tests that Timers properly track sessions when an app becomes top and is closed.
+     */
+    @Test
+    public void testIsWithinEJQuotaLocked_TopApp() {
+        setDischarging();
+        JobStatus js = createExpeditedJobStatus("testIsWithinEJQuotaLocked_TopApp", 1);
+        setStandbyBucket(FREQUENT_INDEX, js);
+        setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_FREQUENT_MS, 10 * MINUTE_IN_MILLIS);
+        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - (HOUR_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5), true);
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - (30 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5), true);
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - (5 * MINUTE_IN_MILLIS), 4 * MINUTE_IN_MILLIS, 5), true);
+        setProcessState(ActivityManager.PROCESS_STATE_RECEIVER);
+        synchronized (mQuotaController.mLock) {
+            assertFalse(mQuotaController.isWithinEJQuotaLocked(js));
+        }
+
+        final long gracePeriodMs = 15 * SECOND_IN_MILLIS;
+        setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TOP_APP_MS, gracePeriodMs);
+        Handler handler = mQuotaController.getHandler();
+        spyOn(handler);
+
+        // Apps on top should be able to schedule & start EJs, even if they're out
+        // of quota (as long as they are in the top grace period).
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        synchronized (mQuotaController.mLock) {
+            assertTrue(mQuotaController.isWithinEJQuotaLocked(js));
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        // Still in grace period
+        synchronized (mQuotaController.mLock) {
+            assertTrue(mQuotaController.isWithinEJQuotaLocked(js));
+        }
+        advanceElapsedClock(6 * SECOND_IN_MILLIS);
+        // Out of grace period.
+        synchronized (mQuotaController.mLock) {
+            assertFalse(mQuotaController.isWithinEJQuotaLocked(js));
+        }
+    }
+
     @Test
     public void testMaybeScheduleCleanupAlarmLocked() {
         // No sessions saved yet.
@@ -2651,14 +2712,16 @@
         setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_FREQUENT_MS, 1 * HOUR_IN_MILLIS);
         setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RARE_MS, 30 * MINUTE_IN_MILLIS);
         setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RESTRICTED_MS, 27 * MINUTE_IN_MILLIS);
-        setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_SPECIAL_ADDITION_MS, 10 * HOUR_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_ADDITION_INSTALLER_MS, 7 * HOUR_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_ADDITION_SPECIAL_MS, 10 * HOUR_IN_MILLIS);
         setDeviceConfigLong(QcConstants.KEY_EJ_WINDOW_SIZE_MS, 12 * HOUR_IN_MILLIS);
         setDeviceConfigLong(QcConstants.KEY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS, 10 * MINUTE_IN_MILLIS);
         setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_TOP_APP_MS, 87 * SECOND_IN_MILLIS);
         setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_INTERACTION_MS, 86 * SECOND_IN_MILLIS);
         setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_NOTIFICATION_SEEN_MS, 85 * SECOND_IN_MILLIS);
-        setDeviceConfigLong(QcConstants.KEY_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS,
+        setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS,
                 84 * SECOND_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TOP_APP_MS, 83 * SECOND_IN_MILLIS);
 
         assertEquals(5 * MINUTE_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs());
         assertEquals(2 * MINUTE_IN_MILLIS, mQuotaController.getInQuotaBufferMs());
@@ -2691,13 +2754,15 @@
         assertEquals(HOUR_IN_MILLIS, mQuotaController.getEJLimitsMs()[FREQUENT_INDEX]);
         assertEquals(30 * MINUTE_IN_MILLIS, mQuotaController.getEJLimitsMs()[RARE_INDEX]);
         assertEquals(27 * MINUTE_IN_MILLIS, mQuotaController.getEJLimitsMs()[RESTRICTED_INDEX]);
-        assertEquals(10 * HOUR_IN_MILLIS, mQuotaController.getEjLimitSpecialAdditionMs());
+        assertEquals(7 * HOUR_IN_MILLIS, mQuotaController.getEjLimitAdditionInstallerMs());
+        assertEquals(10 * HOUR_IN_MILLIS, mQuotaController.getEjLimitAdditionSpecialMs());
         assertEquals(12 * HOUR_IN_MILLIS, mQuotaController.getEJLimitWindowSizeMs());
         assertEquals(10 * MINUTE_IN_MILLIS, mQuotaController.getEJTopAppTimeChunkSizeMs());
         assertEquals(87 * SECOND_IN_MILLIS, mQuotaController.getEJRewardTopAppMs());
         assertEquals(86 * SECOND_IN_MILLIS, mQuotaController.getEJRewardInteractionMs());
         assertEquals(85 * SECOND_IN_MILLIS, mQuotaController.getEJRewardNotificationSeenMs());
-        assertEquals(84 * SECOND_IN_MILLIS, mQuotaController.getEJTempAllowlistGracePeriodMs());
+        assertEquals(84 * SECOND_IN_MILLIS, mQuotaController.getEJGracePeriodTempAllowlistMs());
+        assertEquals(83 * SECOND_IN_MILLIS, mQuotaController.getEJGracePeriodTopAppMs());
     }
 
     @Test
@@ -2731,13 +2796,15 @@
         setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_FREQUENT_MS, -1);
         setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RARE_MS, -1);
         setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RESTRICTED_MS, -1);
-        setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_SPECIAL_ADDITION_MS, -1);
+        setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_ADDITION_INSTALLER_MS, -1);
+        setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_ADDITION_SPECIAL_MS, -1);
         setDeviceConfigLong(QcConstants.KEY_EJ_WINDOW_SIZE_MS, -1);
         setDeviceConfigLong(QcConstants.KEY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS, -1);
         setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_TOP_APP_MS, -1);
         setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_INTERACTION_MS, -1);
         setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_NOTIFICATION_SEEN_MS, -1);
-        setDeviceConfigLong(QcConstants.KEY_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS, -1);
+        setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS, -1);
+        setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TOP_APP_MS, -1);
 
         assertEquals(MINUTE_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs());
         assertEquals(0, mQuotaController.getInQuotaBufferMs());
@@ -2767,13 +2834,15 @@
         assertEquals(10 * MINUTE_IN_MILLIS, mQuotaController.getEJLimitsMs()[FREQUENT_INDEX]);
         assertEquals(10 * MINUTE_IN_MILLIS, mQuotaController.getEJLimitsMs()[RARE_INDEX]);
         assertEquals(5 * MINUTE_IN_MILLIS, mQuotaController.getEJLimitsMs()[RESTRICTED_INDEX]);
-        assertEquals(0, mQuotaController.getEjLimitSpecialAdditionMs());
+        assertEquals(0, mQuotaController.getEjLimitAdditionInstallerMs());
+        assertEquals(0, mQuotaController.getEjLimitAdditionSpecialMs());
         assertEquals(HOUR_IN_MILLIS, mQuotaController.getEJLimitWindowSizeMs());
         assertEquals(1, mQuotaController.getEJTopAppTimeChunkSizeMs());
         assertEquals(10 * SECOND_IN_MILLIS, mQuotaController.getEJRewardTopAppMs());
         assertEquals(5 * SECOND_IN_MILLIS, mQuotaController.getEJRewardInteractionMs());
         assertEquals(0, mQuotaController.getEJRewardNotificationSeenMs());
-        assertEquals(0, mQuotaController.getEJTempAllowlistGracePeriodMs());
+        assertEquals(0, mQuotaController.getEJGracePeriodTempAllowlistMs());
+        assertEquals(0, mQuotaController.getEJGracePeriodTopAppMs());
 
         // Invalid configurations.
         // In_QUOTA_BUFFER should never be greater than ALLOWED_TIME_PER_PERIOD
@@ -2801,13 +2870,15 @@
         setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_FREQUENT_MS, 25 * HOUR_IN_MILLIS);
         setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RARE_MS, 25 * HOUR_IN_MILLIS);
         setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RESTRICTED_MS, 25 * HOUR_IN_MILLIS);
-        setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_SPECIAL_ADDITION_MS, 25 * HOUR_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_ADDITION_INSTALLER_MS, 25 * HOUR_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_ADDITION_SPECIAL_MS, 25 * HOUR_IN_MILLIS);
         setDeviceConfigLong(QcConstants.KEY_EJ_WINDOW_SIZE_MS, 25 * HOUR_IN_MILLIS);
         setDeviceConfigLong(QcConstants.KEY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS, 25 * HOUR_IN_MILLIS);
         setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_TOP_APP_MS, 25 * HOUR_IN_MILLIS);
         setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_INTERACTION_MS, 25 * HOUR_IN_MILLIS);
         setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_NOTIFICATION_SEEN_MS, 25 * HOUR_IN_MILLIS);
-        setDeviceConfigLong(QcConstants.KEY_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS, 25 * HOUR_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS, 25 * HOUR_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TOP_APP_MS, 25 * HOUR_IN_MILLIS);
 
         assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs());
         assertEquals(5 * MINUTE_IN_MILLIS, mQuotaController.getInQuotaBufferMs());
@@ -2827,13 +2898,15 @@
         assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getEJLimitsMs()[FREQUENT_INDEX]);
         assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getEJLimitsMs()[RARE_INDEX]);
         assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getEJLimitsMs()[RESTRICTED_INDEX]);
-        assertEquals(0, mQuotaController.getEjLimitSpecialAdditionMs());
+        assertEquals(0, mQuotaController.getEjLimitAdditionInstallerMs());
+        assertEquals(0, mQuotaController.getEjLimitAdditionSpecialMs());
         assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getEJLimitWindowSizeMs());
         assertEquals(15 * MINUTE_IN_MILLIS, mQuotaController.getEJTopAppTimeChunkSizeMs());
         assertEquals(15 * MINUTE_IN_MILLIS, mQuotaController.getEJRewardTopAppMs());
         assertEquals(15 * MINUTE_IN_MILLIS, mQuotaController.getEJRewardInteractionMs());
         assertEquals(5 * MINUTE_IN_MILLIS, mQuotaController.getEJRewardNotificationSeenMs());
-        assertEquals(HOUR_IN_MILLIS, mQuotaController.getEJTempAllowlistGracePeriodMs());
+        assertEquals(HOUR_IN_MILLIS, mQuotaController.getEJGracePeriodTempAllowlistMs());
+        assertEquals(HOUR_IN_MILLIS, mQuotaController.getEJGracePeriodTopAppMs());
     }
 
     /** Tests that TimingSessions aren't saved when the device is charging. */
@@ -3433,7 +3506,7 @@
         setDischarging();
         setProcessState(ActivityManager.PROCESS_STATE_RECEIVER);
         final long gracePeriodMs = 15 * SECOND_IN_MILLIS;
-        setDeviceConfigLong(QcConstants.KEY_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS, gracePeriodMs);
+        setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS, gracePeriodMs);
         Handler handler = mQuotaController.getHandler();
         spyOn(handler);
 
@@ -3898,9 +3971,16 @@
     }
 
     @Test
-    public void testGetRemainingEJExecutionTimeLocked_SpecialApp() {
-        doReturn(new String[]{SOURCE_PACKAGE}).when(mPackageManagerInternal)
-                .getKnownPackageNames(eq(PackageManagerInternal.PACKAGE_VERIFIER), anyInt());
+    public void testGetRemainingEJExecutionTimeLocked_Installer() {
+        PackageInfo pi = new PackageInfo();
+        pi.packageName = SOURCE_PACKAGE;
+        pi.requestedPermissions = new String[]{Manifest.permission.INSTALL_PACKAGES};
+        pi.requestedPermissionsFlags = new int[]{PackageInfo.REQUESTED_PERMISSION_GRANTED};
+        pi.applicationInfo = new ApplicationInfo();
+        pi.applicationInfo.uid = mSourceUid;
+        doReturn(List.of(pi)).when(mPackageManager).getInstalledPackagesAsUser(anyInt(), anyInt());
+        doReturn(PackageManager.PERMISSION_GRANTED).when(mContext).checkPermission(
+                eq(Manifest.permission.INSTALL_PACKAGES), anyInt(), eq(mSourceUid));
         mQuotaController.onSystemServicesReady();
 
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
@@ -3921,7 +4001,7 @@
             setStandbyBucket(i);
             assertEquals("Got wrong remaining EJ execution time for bucket #" + i,
                     i == NEVER_INDEX ? 0
-                            : (limits[i] + mQuotaController.getEjLimitSpecialAdditionMs()
+                            : (limits[i] + mQuotaController.getEjLimitAdditionInstallerMs()
                                     - 5 * MINUTE_IN_MILLIS),
                     mQuotaController.getRemainingEJExecutionTimeLocked(
                             SOURCE_USER_ID, SOURCE_PACKAGE));
@@ -4910,6 +4990,7 @@
     @Test
     public void testEJTimerTracking_TopAndNonTop() {
         setDischarging();
+        setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TOP_APP_MS, 0);
 
         JobStatus jobBg1 = createExpeditedJobStatus("testEJTimerTracking_TopAndNonTop", 1);
         JobStatus jobBg2 = createExpeditedJobStatus("testEJTimerTracking_TopAndNonTop", 2);
@@ -5032,7 +5113,7 @@
         setDischarging();
         setProcessState(ActivityManager.PROCESS_STATE_RECEIVER);
         final long gracePeriodMs = 15 * SECOND_IN_MILLIS;
-        setDeviceConfigLong(QcConstants.KEY_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS, gracePeriodMs);
+        setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS, gracePeriodMs);
         Handler handler = mQuotaController.getHandler();
         spyOn(handler);
 
@@ -5134,11 +5215,158 @@
     }
 
     /**
+     * Tests that Timers properly track sessions when TOP state and temp allowlisting overlaps.
+     */
+    @Test
+    @LargeTest
+    public void testEJTimerTracking_TopAndTempAllowlisting() throws Exception {
+        setDischarging();
+        setProcessState(ActivityManager.PROCESS_STATE_RECEIVER);
+        final long gracePeriodMs = 5 * SECOND_IN_MILLIS;
+        setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TEMP_ALLOWLIST_MS, gracePeriodMs);
+        setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TOP_APP_MS, gracePeriodMs);
+        Handler handler = mQuotaController.getHandler();
+        spyOn(handler);
+
+        JobStatus job1 = createExpeditedJobStatus("testEJTimerTracking_TopAndTempAllowlisting", 1);
+        JobStatus job2 = createExpeditedJobStatus("testEJTimerTracking_TopAndTempAllowlisting", 2);
+        JobStatus job3 = createExpeditedJobStatus("testEJTimerTracking_TopAndTempAllowlisting", 3);
+        JobStatus job4 = createExpeditedJobStatus("testEJTimerTracking_TopAndTempAllowlisting", 4);
+        JobStatus job5 = createExpeditedJobStatus("testEJTimerTracking_TopAndTempAllowlisting", 5);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(job1, null);
+        }
+        assertNull(mQuotaController.getEJTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+        List<TimingSession> expected = new ArrayList<>();
+
+        // Case 1: job starts in TA grace period then app becomes TOP
+        long start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        mTempAllowlistListener.onAppAdded(mSourceUid);
+        mTempAllowlistListener.onAppRemoved(mSourceUid);
+        advanceElapsedClock(gracePeriodMs / 2);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(job1);
+        }
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        advanceElapsedClock(gracePeriodMs);
+        // Wait for the grace period to expire so the handler can process the message.
+        Thread.sleep(gracePeriodMs);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(job1, job1, true);
+        }
+        assertNull(mQuotaController.getEJTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        advanceElapsedClock(gracePeriodMs);
+
+        // Case 2: job starts in TOP grace period then is TAed
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+        advanceElapsedClock(gracePeriodMs / 2);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(job2, null);
+            mQuotaController.prepareForExecutionLocked(job2);
+        }
+        mTempAllowlistListener.onAppAdded(mSourceUid);
+        advanceElapsedClock(gracePeriodMs);
+        // Wait for the grace period to expire so the handler can process the message.
+        Thread.sleep(gracePeriodMs);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(job2, null, false);
+        }
+        assertNull(mQuotaController.getEJTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        advanceElapsedClock(gracePeriodMs);
+
+        // Case 3: job starts in TA grace period then app becomes TOP; job ends after TOP grace
+        mTempAllowlistListener.onAppAdded(mSourceUid);
+        mTempAllowlistListener.onAppRemoved(mSourceUid);
+        advanceElapsedClock(gracePeriodMs / 2);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(job3, null);
+            mQuotaController.prepareForExecutionLocked(job3);
+        }
+        advanceElapsedClock(SECOND_IN_MILLIS);
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        advanceElapsedClock(gracePeriodMs);
+        // Wait for the grace period to expire so the handler can process the message.
+        Thread.sleep(gracePeriodMs);
+        setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+        advanceElapsedClock(gracePeriodMs);
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        // Wait for the grace period to expire so the handler can process the message.
+        Thread.sleep(2 * gracePeriodMs);
+        advanceElapsedClock(gracePeriodMs);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(job3, job3, true);
+        }
+        expected.add(createTimingSession(start, gracePeriodMs, 1));
+        assertEquals(expected,
+                mQuotaController.getEJTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        advanceElapsedClock(gracePeriodMs);
+
+        // Case 4: job starts in TOP grace period then app becomes TAed; job ends after TA grace
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+        advanceElapsedClock(gracePeriodMs / 2);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(job4, null);
+            mQuotaController.prepareForExecutionLocked(job4);
+        }
+        advanceElapsedClock(SECOND_IN_MILLIS);
+        mTempAllowlistListener.onAppAdded(mSourceUid);
+        advanceElapsedClock(gracePeriodMs);
+        // Wait for the grace period to expire so the handler can process the message.
+        Thread.sleep(gracePeriodMs);
+        mTempAllowlistListener.onAppRemoved(mSourceUid);
+        advanceElapsedClock(gracePeriodMs);
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        // Wait for the grace period to expire so the handler can process the message.
+        Thread.sleep(2 * gracePeriodMs);
+        advanceElapsedClock(gracePeriodMs);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(job4, job4, true);
+        }
+        expected.add(createTimingSession(start, gracePeriodMs, 1));
+        assertEquals(expected,
+                mQuotaController.getEJTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        advanceElapsedClock(gracePeriodMs);
+
+        // Case 5: job starts during overlapping grace period
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        advanceElapsedClock(SECOND_IN_MILLIS);
+        setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+        advanceElapsedClock(SECOND_IN_MILLIS);
+        mTempAllowlistListener.onAppAdded(mSourceUid);
+        advanceElapsedClock(SECOND_IN_MILLIS);
+        mTempAllowlistListener.onAppRemoved(mSourceUid);
+        advanceElapsedClock(gracePeriodMs - SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(job5, null);
+            mQuotaController.prepareForExecutionLocked(job5);
+        }
+        advanceElapsedClock(SECOND_IN_MILLIS);
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        // Wait for the grace period to expire so the handler can process the message.
+        Thread.sleep(2 * gracePeriodMs);
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(job5, job5, true);
+        }
+        expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+        assertEquals(expected,
+                mQuotaController.getEJTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+    }
+
+    /**
      * Tests that expedited jobs aren't stopped when an app runs out of quota.
      */
     @Test
     public void testEJTracking_OutOfQuota_ForegroundAndBackground() {
         setDischarging();
+        setDeviceConfigLong(QcConstants.KEY_EJ_GRACE_PERIOD_TOP_APP_MS, 0);
 
         JobStatus jobBg =
                 createExpeditedJobStatus("testEJTracking_OutOfQuota_ForegroundAndBackground", 1);
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index e853fd3..17c6b6f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -163,7 +163,7 @@
     /** Collection of mocks used for PackageManagerService tests. */
 
     class Mocks {
-        val lock = Any()
+        val lock = PackageManagerTracedLock()
         val installLock = Any()
         val injector: PackageManagerService.Injector = mock()
         val systemWrapper: PackageManagerService.SystemWrapper = mock()
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/dex/OWNERS b/services/tests/mockingservicestests/src/com/android/server/pm/dex/OWNERS
index 5a4431e..5492dc8 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/dex/OWNERS
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/dex/OWNERS
@@ -1,2 +1 @@
-calin@google.com
-ngeoffray@google.com
+include platform/art:/OWNERS
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java b/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
index 6814c050a..2eb9e34 100644
--- a/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
@@ -524,7 +524,7 @@
         assertTrue(outLaunched.value);
 
         verify(mUiEventLogger, times(1))
-                .log(GestureLauncherService.GestureLauncherEvent.GESTURE_PANIC_TAP_POWER);
+                .log(GestureLauncherService.GestureLauncherEvent.GESTURE_EMERGENCY_TAP_POWER);
         verify(mStatusBarManagerInternal).onEmergencyActionLaunchGestureDetected();
 
         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
@@ -578,7 +578,7 @@
         assertTrue(intercepted);
 
         verify(mUiEventLogger, times(1))
-                .log(GestureLauncherService.GestureLauncherEvent.GESTURE_PANIC_TAP_POWER);
+                .log(GestureLauncherService.GestureLauncherEvent.GESTURE_EMERGENCY_TAP_POWER);
         verify(mStatusBarManagerInternal).onEmergencyActionLaunchGestureDetected();
 
         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java
index c7e7c78..45f43e8 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java
@@ -16,6 +16,8 @@
 
 package com.android.server.accessibility;
 
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.TestCase.assertNull;
 import static junit.framework.TestCase.assertTrue;
@@ -30,6 +32,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -47,10 +50,13 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.testing.DexmakerShareClassLoaderRule;
+import android.testing.TestableContext;
 import android.util.ArraySet;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityWindowInfo;
 
+import com.android.internal.R;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -58,7 +64,9 @@
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
 
 /**
@@ -72,9 +80,9 @@
     private static final int APP_UID = 10400;
     private static final int APP_PID = 2000;
     private static final int SYSTEM_PID = 558;
-
-    private static final String PERMISSION = "test-permission";
-    private static final String FUNCTION = "test-function-name";
+    private static final int TEST_USER_ID = UserHandle.USER_SYSTEM;
+    private static final ComponentName TEST_COMPONENT_NAME = new ComponentName(
+            "com.android.server.accessibility", "AccessibilitySecurityPolicyTest");
 
     private static final int[] ALWAYS_DISPATCH_EVENTS = {
             AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
@@ -108,29 +116,51 @@
 
     private AccessibilitySecurityPolicy mA11ySecurityPolicy;
 
+    @Rule
+    public final TestableContext mContext = new TestableContext(
+            getInstrumentation().getTargetContext(), null);
+
     // To mock package-private class
-    @Rule public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
+    @Rule
+    public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
             new DexmakerShareClassLoaderRule();
 
-    @Mock private Context mMockContext;
-    @Mock private PackageManager mMockPackageManager;
-    @Mock private UserManager mMockUserManager;
-    @Mock private AppOpsManager mMockAppOpsManager;
-    @Mock private AccessibilityServiceConnection mMockA11yServiceConnection;
-    @Mock private AccessibilityWindowManager mMockA11yWindowManager;
-    @Mock private AppWidgetManagerInternal mMockAppWidgetManager;
-    @Mock private AccessibilitySecurityPolicy.AccessibilityUserManager mMockA11yUserManager;
+    @Mock
+    private PackageManager mMockPackageManager;
+    @Mock
+    private UserManager mMockUserManager;
+    @Mock
+    private AppOpsManager mMockAppOpsManager;
+    @Mock
+    private AccessibilityServiceConnection mMockA11yServiceConnection;
+    @Mock
+    private AccessibilityWindowManager mMockA11yWindowManager;
+    @Mock
+    private AppWidgetManagerInternal mMockAppWidgetManager;
+    @Mock
+    private AccessibilitySecurityPolicy.AccessibilityUserManager mMockA11yUserManager;
+    @Mock
+    private AccessibilityServiceInfo mMockA11yServiceInfo;
+    @Mock
+    private PolicyWarningUIController mPolicyWarningUIController;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
-        when(mMockContext.getSystemService(Context.USER_SERVICE)).thenReturn(mMockUserManager);
-        when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mMockAppOpsManager);
+        mContext.setMockPackageManager(mMockPackageManager);
+        mContext.addMockSystemService(Context.USER_SERVICE, mMockUserManager);
+        mContext.addMockSystemService(Context.APP_OPS_SERVICE, mMockAppOpsManager);
+        mContext.getOrCreateTestableResources().addOverride(
+                R.dimen.accessibility_focus_highlight_stroke_width, 1);
 
-        mA11ySecurityPolicy = new AccessibilitySecurityPolicy(mMockContext, mMockA11yUserManager);
+        when(mMockA11yServiceInfo.getComponentName()).thenReturn(TEST_COMPONENT_NAME);
+        when(mMockA11yServiceConnection.getServiceInfo()).thenReturn(mMockA11yServiceInfo);
+
+        mA11ySecurityPolicy = new AccessibilitySecurityPolicy(
+                mPolicyWarningUIController, mContext, mMockA11yUserManager);
         mA11ySecurityPolicy.setAccessibilityWindowManager(mMockA11yWindowManager);
         mA11ySecurityPolicy.setAppWidgetManager(mMockAppWidgetManager);
+        mA11ySecurityPolicy.onSwitchUserLocked(TEST_USER_ID, new HashSet<>());
 
         when(mMockA11yWindowManager.resolveParentWindowIdLocked(anyInt())).then(returnsFirstArg());
     }
@@ -141,7 +171,7 @@
             final AccessibilityEvent event = AccessibilityEvent.obtain(ALWAYS_DISPATCH_EVENTS[i]);
             assertTrue("Should dispatch [" + event + "]",
                     mA11ySecurityPolicy.canDispatchAccessibilityEventLocked(
-                            UserHandle.USER_SYSTEM,
+                            TEST_USER_ID,
                             event));
         }
     }
@@ -154,28 +184,28 @@
             event.setWindowId(invalidWindowId);
             assertFalse("Shouldn't dispatch [" + event + "]",
                     mA11ySecurityPolicy.canDispatchAccessibilityEventLocked(
-                            UserHandle.USER_SYSTEM,
+                            TEST_USER_ID,
                             event));
         }
     }
 
     @Test
     public void canDispatchAccessibilityEvent_otherEvents_windowIdIsActive_returnTrue() {
-        when(mMockA11yWindowManager.getActiveWindowId(UserHandle.USER_SYSTEM))
+        when(mMockA11yWindowManager.getActiveWindowId(TEST_USER_ID))
                 .thenReturn(WINDOWID);
         for (int i = 0; i < OTHER_EVENTS.length; i++) {
             final AccessibilityEvent event = AccessibilityEvent.obtain(OTHER_EVENTS[i]);
             event.setWindowId(WINDOWID);
             assertTrue("Should dispatch [" + event + "]",
                     mA11ySecurityPolicy.canDispatchAccessibilityEventLocked(
-                            UserHandle.USER_SYSTEM,
+                            TEST_USER_ID,
                             event));
         }
     }
 
     @Test
     public void canDispatchAccessibilityEvent_otherEvents_windowIdExist_returnTrue() {
-        when(mMockA11yWindowManager.getActiveWindowId(UserHandle.USER_SYSTEM))
+        when(mMockA11yWindowManager.getActiveWindowId(TEST_USER_ID))
                 .thenReturn(WINDOWID2);
         when(mMockA11yWindowManager.findA11yWindowInfoByIdLocked(WINDOWID))
                 .thenReturn(AccessibilityWindowInfo.obtain());
@@ -184,7 +214,7 @@
             event.setWindowId(WINDOWID);
             assertTrue("Should dispatch [" + event + "]",
                     mA11ySecurityPolicy.canDispatchAccessibilityEventLocked(
-                            UserHandle.USER_SYSTEM,
+                            TEST_USER_ID,
                             event));
         }
     }
@@ -192,24 +222,24 @@
     @Test
     public void resolveValidReportedPackage_nullPkgName_returnNull() {
         assertNull(mA11ySecurityPolicy.resolveValidReportedPackageLocked(
-                null, Process.SYSTEM_UID, UserHandle.USER_SYSTEM, SYSTEM_PID));
+                null, Process.SYSTEM_UID, TEST_USER_ID, SYSTEM_PID));
     }
 
     @Test
     public void resolveValidReportedPackage_uidIsSystem_returnPkgName() {
         assertEquals(mA11ySecurityPolicy.resolveValidReportedPackageLocked(
-                PACKAGE_NAME, Process.SYSTEM_UID, UserHandle.USER_SYSTEM, SYSTEM_PID),
+                PACKAGE_NAME, Process.SYSTEM_UID, TEST_USER_ID, SYSTEM_PID),
                 PACKAGE_NAME);
     }
 
     @Test
     public void resolveValidReportedPackage_uidAndPkgNameMatched_returnPkgName()
             throws PackageManager.NameNotFoundException {
-        when(mMockPackageManager.getPackageUidAsUser(PACKAGE_NAME, UserHandle.USER_SYSTEM))
+        when(mMockPackageManager.getPackageUidAsUser(PACKAGE_NAME, TEST_USER_ID))
                 .thenReturn(APP_UID);
 
         assertEquals(mA11ySecurityPolicy.resolveValidReportedPackageLocked(
-                PACKAGE_NAME, APP_UID, UserHandle.USER_SYSTEM, APP_PID),
+                PACKAGE_NAME, APP_UID, TEST_USER_ID, APP_PID),
                 PACKAGE_NAME);
     }
 
@@ -225,11 +255,11 @@
 
         when(mMockAppWidgetManager.getHostedWidgetPackages(widgetHostUid))
                 .thenReturn(widgetPackages);
-        when(mMockPackageManager.getPackageUidAsUser(hostPackageName, UserHandle.USER_SYSTEM))
+        when(mMockPackageManager.getPackageUidAsUser(hostPackageName, TEST_USER_ID))
                 .thenReturn(widgetHostUid);
 
         assertEquals(mA11ySecurityPolicy.resolveValidReportedPackageLocked(
-                widgetPackageName, widgetHostUid, UserHandle.USER_SYSTEM, widgetHostPid),
+                widgetPackageName, widgetHostUid, TEST_USER_ID, widgetHostPid),
                 widgetPackageName);
     }
 
@@ -240,16 +270,16 @@
         final String[] uidPackages = {PACKAGE_NAME, PACKAGE_NAME2};
         when(mMockPackageManager.getPackagesForUid(APP_UID))
                 .thenReturn(uidPackages);
-        when(mMockPackageManager.getPackageUidAsUser(invalidPackageName, UserHandle.USER_SYSTEM))
+        when(mMockPackageManager.getPackageUidAsUser(invalidPackageName, TEST_USER_ID))
                 .thenThrow(PackageManager.NameNotFoundException.class);
         when(mMockAppWidgetManager.getHostedWidgetPackages(APP_UID))
                 .thenReturn(new ArraySet<>());
-        when(mMockContext.checkPermission(
-                eq(Manifest.permission.ACT_AS_PACKAGE_FOR_ACCESSIBILITY), anyInt(), eq(APP_UID)))
-                .thenReturn(PackageManager.PERMISSION_DENIED);
+        mContext.getTestablePermissions().setPermission(
+                Manifest.permission.ACT_AS_PACKAGE_FOR_ACCESSIBILITY,
+                PackageManager.PERMISSION_DENIED);
 
         assertEquals(PACKAGE_NAME, mA11ySecurityPolicy.resolveValidReportedPackageLocked(
-                invalidPackageName, APP_UID, UserHandle.USER_SYSTEM, APP_PID));
+                invalidPackageName, APP_UID, TEST_USER_ID, APP_PID));
     }
 
     @Test
@@ -260,16 +290,16 @@
         final String[] uidPackages = {PACKAGE_NAME};
         when(mMockPackageManager.getPackagesForUid(APP_UID))
                 .thenReturn(uidPackages);
-        when(mMockPackageManager.getPackageUidAsUser(wantedPackageName, UserHandle.USER_SYSTEM))
+        when(mMockPackageManager.getPackageUidAsUser(wantedPackageName, TEST_USER_ID))
                 .thenReturn(wantedUid);
         when(mMockAppWidgetManager.getHostedWidgetPackages(APP_UID))
                 .thenReturn(new ArraySet<>());
-        when(mMockContext.checkPermission(
-                eq(Manifest.permission.ACT_AS_PACKAGE_FOR_ACCESSIBILITY), anyInt(), eq(APP_UID)))
-                .thenReturn(PackageManager.PERMISSION_GRANTED);
+        mContext.getTestablePermissions().setPermission(
+                Manifest.permission.ACT_AS_PACKAGE_FOR_ACCESSIBILITY,
+                PackageManager.PERMISSION_GRANTED);
 
         assertEquals(wantedPackageName, mA11ySecurityPolicy.resolveValidReportedPackageLocked(
-                wantedPackageName, APP_UID, UserHandle.USER_SYSTEM, APP_PID));
+                wantedPackageName, APP_UID, TEST_USER_ID, APP_PID));
     }
 
     @Test
@@ -280,16 +310,16 @@
         final String[] uidPackages = {PACKAGE_NAME};
         when(mMockPackageManager.getPackagesForUid(APP_UID))
                 .thenReturn(uidPackages);
-        when(mMockPackageManager.getPackageUidAsUser(wantedPackageName, UserHandle.USER_SYSTEM))
+        when(mMockPackageManager.getPackageUidAsUser(wantedPackageName, TEST_USER_ID))
                 .thenReturn(wantedUid);
         when(mMockAppWidgetManager.getHostedWidgetPackages(APP_UID))
                 .thenReturn(new ArraySet<>());
-        when(mMockContext.checkPermission(
-                eq(Manifest.permission.ACT_AS_PACKAGE_FOR_ACCESSIBILITY), anyInt(), eq(APP_UID)))
-                .thenReturn(PackageManager.PERMISSION_DENIED);
+        mContext.getTestablePermissions().setPermission(
+                Manifest.permission.ACT_AS_PACKAGE_FOR_ACCESSIBILITY,
+                PackageManager.PERMISSION_DENIED);
 
         assertEquals(PACKAGE_NAME, mA11ySecurityPolicy.resolveValidReportedPackageLocked(
-                wantedPackageName, APP_UID, UserHandle.USER_SYSTEM, APP_PID));
+                wantedPackageName, APP_UID, TEST_USER_ID, APP_PID));
     }
 
     @Test
@@ -301,7 +331,7 @@
     @Test
     public void computeValidReportedPackages_uidIsAppWidgetHost_returnTargetAndWidgetName() {
         final int widgetHostUid = APP_UID;
-        final String targetPackageName =  PACKAGE_NAME;
+        final String targetPackageName = PACKAGE_NAME;
         final String widgetPackageName = PACKAGE_NAME2;
         final ArraySet<String> widgetPackages = new ArraySet<>();
         widgetPackages.add(widgetPackageName);
@@ -320,7 +350,7 @@
         when(mMockA11yServiceConnection.getCapabilities())
                 .thenReturn(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT);
 
-        assertFalse(mA11ySecurityPolicy.canGetAccessibilityNodeInfoLocked(UserHandle.USER_SYSTEM,
+        assertFalse(mA11ySecurityPolicy.canGetAccessibilityNodeInfoLocked(TEST_USER_ID,
                 mMockA11yServiceConnection, invalidWindowId));
     }
 
@@ -328,10 +358,10 @@
     public void canGetAccessibilityNodeInfo_hasCapAndWindowIsActive_returnTrue() {
         when(mMockA11yServiceConnection.getCapabilities())
                 .thenReturn(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT);
-        when(mMockA11yWindowManager.getActiveWindowId(UserHandle.USER_SYSTEM))
+        when(mMockA11yWindowManager.getActiveWindowId(TEST_USER_ID))
                 .thenReturn(WINDOWID);
 
-        assertTrue(mA11ySecurityPolicy.canGetAccessibilityNodeInfoLocked(UserHandle.USER_SYSTEM,
+        assertTrue(mA11ySecurityPolicy.canGetAccessibilityNodeInfoLocked(TEST_USER_ID,
                 mMockA11yServiceConnection, WINDOWID));
     }
 
@@ -339,12 +369,12 @@
     public void canGetAccessibilityNodeInfo_hasCapAndWindowExist_returnTrue() {
         when(mMockA11yServiceConnection.getCapabilities())
                 .thenReturn(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT);
-        when(mMockA11yWindowManager.getActiveWindowId(UserHandle.USER_SYSTEM))
+        when(mMockA11yWindowManager.getActiveWindowId(TEST_USER_ID))
                 .thenReturn(WINDOWID2);
         when(mMockA11yWindowManager.findA11yWindowInfoByIdLocked(WINDOWID))
                 .thenReturn(AccessibilityWindowInfo.obtain());
 
-        assertTrue(mA11ySecurityPolicy.canGetAccessibilityNodeInfoLocked(UserHandle.USER_SYSTEM,
+        assertTrue(mA11ySecurityPolicy.canGetAccessibilityNodeInfoLocked(TEST_USER_ID,
                 mMockA11yServiceConnection, WINDOWID));
     }
 
@@ -464,8 +494,10 @@
                 .thenReturn(currentUserId);
         doReturn(callingParentId).when(spySecurityPolicy).resolveProfileParentLocked(
                 callingUserId);
-        when(mMockContext.checkCallingPermission(any()))
-                .thenReturn(PackageManager.PERMISSION_DENIED);
+        mContext.getTestablePermissions().setPermission(Manifest.permission.INTERACT_ACROSS_USERS,
+                PackageManager.PERMISSION_DENIED);
+        mContext.getTestablePermissions().setPermission(
+                Manifest.permission.INTERACT_ACROSS_USERS_FULL, PackageManager.PERMISSION_DENIED);
 
         spySecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
                 UserHandle.USER_CURRENT_OR_SELF);
@@ -482,8 +514,8 @@
                 .thenReturn(currentUserId);
         doReturn(callingParentId).when(spySecurityPolicy).resolveProfileParentLocked(
                 callingUserId);
-        when(mMockContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS))
-                .thenReturn(PackageManager.PERMISSION_GRANTED);
+        mContext.getTestablePermissions().setPermission(Manifest.permission.INTERACT_ACROSS_USERS,
+                PackageManager.PERMISSION_GRANTED);
 
         assertEquals(wantedUserId,
                 spySecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(wantedUserId));
@@ -500,8 +532,8 @@
                 .thenReturn(currentUserId);
         doReturn(callingParentId).when(spySecurityPolicy).resolveProfileParentLocked(
                 callingUserId);
-        when(mMockContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL))
-                .thenReturn(PackageManager.PERMISSION_GRANTED);
+        mContext.getTestablePermissions().setPermission(
+                Manifest.permission.INTERACT_ACROSS_USERS_FULL, PackageManager.PERMISSION_GRANTED);
 
         assertEquals(wantedUserId,
                 spySecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(wantedUserId));
@@ -518,10 +550,10 @@
                 .thenReturn(currentUserId);
         doReturn(callingParentId).when(spySecurityPolicy).resolveProfileParentLocked(
                 callingUserId);
-        when(mMockContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS))
-                .thenReturn(PackageManager.PERMISSION_DENIED);
-        when(mMockContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL))
-                .thenReturn(PackageManager.PERMISSION_DENIED);
+        mContext.getTestablePermissions().setPermission(Manifest.permission.INTERACT_ACROSS_USERS,
+                PackageManager.PERMISSION_DENIED);
+        mContext.getTestablePermissions().setPermission(
+                Manifest.permission.INTERACT_ACROSS_USERS_FULL, PackageManager.PERMISSION_DENIED);
 
         spySecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(wantedUserId);
     }
@@ -562,4 +594,57 @@
                 APP_UID, PACKAGE_NAME);
     }
 
+    @Test
+    public void onBoundServicesChanged_bindA11yCategoryService_noUIControllerAction() {
+        final ArrayList<AccessibilityServiceConnection> boundServices = new ArrayList<>();
+        boundServices.add(mMockA11yServiceConnection);
+        when(mMockA11yServiceInfo.isAccessibilityTool()).thenReturn(true);
+
+        mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, boundServices);
+
+        verify(mPolicyWarningUIController, never()).onNonA11yCategoryServiceBound(anyInt(), any());
+    }
+
+    @Test
+    public void onBoundServicesChanged_unbindA11yCategoryService_noUIControllerAction() {
+        onBoundServicesChanged_bindA11yCategoryService_noUIControllerAction();
+
+        mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, new ArrayList<>());
+
+        verify(mPolicyWarningUIController, never()).onNonA11yCategoryServiceUnbound(anyInt(),
+                any());
+    }
+
+    @Test
+    public void onBoundServicesChanged_bindNonA11yCategoryService_activateUIControllerAction() {
+        final ArrayList<AccessibilityServiceConnection> boundServices = new ArrayList<>();
+        boundServices.add(mMockA11yServiceConnection);
+        when(mMockA11yServiceInfo.isAccessibilityTool()).thenReturn(false);
+
+        mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, boundServices);
+
+        verify(mPolicyWarningUIController).onNonA11yCategoryServiceBound(eq(TEST_USER_ID),
+                eq(TEST_COMPONENT_NAME));
+    }
+
+    @Test
+    public void onBoundServicesChanged_unbindNonA11yCategoryService_activateUIControllerAction() {
+        onBoundServicesChanged_bindNonA11yCategoryService_activateUIControllerAction();
+
+        mA11ySecurityPolicy.onBoundServicesChangedLocked(TEST_USER_ID, new ArrayList<>());
+
+        verify(mPolicyWarningUIController).onNonA11yCategoryServiceUnbound(eq(TEST_USER_ID),
+                eq(TEST_COMPONENT_NAME));
+    }
+
+    @Test
+    public void onSwitchUser_differentUser_activateUIControllerAction() {
+        onBoundServicesChanged_bindNonA11yCategoryService_activateUIControllerAction();
+
+        mA11ySecurityPolicy.onSwitchUserLocked(2, new HashSet<>());
+
+        verify(mPolicyWarningUIController).onSwitchUserLocked(eq(2), eq(new HashSet<>()));
+        verify(mPolicyWarningUIController).onNonA11yCategoryServiceUnbound(eq(TEST_USER_ID),
+                eq(TEST_COMPONENT_NAME));
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/PolicyWarningUIControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/PolicyWarningUIControllerTest.java
new file mode 100644
index 0000000..01a641f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/PolicyWarningUIControllerTest.java
@@ -0,0 +1,241 @@
+/*
+ * 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;
+
+import static android.app.AlarmManager.RTC_WAKEUP;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.internal.messages.nano.SystemMessageProto.SystemMessage.NOTE_A11Y_VIEW_AND_CONTROL_ACCESS;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.app.AlarmManager;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.StatusBarManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.testing.TestableContext;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Tests for the {@link PolicyWarningUIController}.
+ */
+public class PolicyWarningUIControllerTest {
+    private static final int TEST_USER_ID = UserHandle.USER_SYSTEM;
+    private static final ComponentName TEST_COMPONENT_NAME = new ComponentName(
+            "com.android.server.accessibility", "PolicyWarningUIControllerTest");
+
+    private final List<AccessibilityServiceInfo> mEnabledServiceList = new ArrayList<>();
+
+    @Rule
+    public final A11yTestableContext mContext = new A11yTestableContext(
+            getInstrumentation().getTargetContext());
+    @Mock
+    private AlarmManager mAlarmManager;
+    @Mock
+    private NotificationManager mNotificationManager;
+    @Mock
+    private StatusBarManager mStatusBarManager;
+    @Mock
+    private AccessibilityServiceInfo mMockA11yServiceInfo;
+    @Mock
+    private ResolveInfo mMockResolveInfo;
+    @Mock
+    private ServiceInfo mMockServiceInfo;
+    @Mock
+    private Context mSpyContext;
+    @Mock
+    private AccessibilitySecurityPolicy mAccessibilitySecurityPolicy;
+
+    private PolicyWarningUIController mPolicyWarningUIController;
+    private FakeNotificationController mFakeNotificationController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext.addMockSystemService(AlarmManager.class, mAlarmManager);
+        mContext.addMockSystemService(NotificationManager.class, mNotificationManager);
+        mContext.addMockSystemService(StatusBarManager.class, mStatusBarManager);
+        mFakeNotificationController = new FakeNotificationController(mContext);
+        mPolicyWarningUIController = new PolicyWarningUIController(
+                getInstrumentation().getTargetContext().getMainThreadHandler(), mContext,
+                mFakeNotificationController);
+        mPolicyWarningUIController.setAccessibilityPolicyManager(mAccessibilitySecurityPolicy);
+        mPolicyWarningUIController.onSwitchUserLocked(TEST_USER_ID, new HashSet<>());
+        mEnabledServiceList.clear();
+        Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                Settings.Secure.NOTIFIED_NON_ACCESSIBILITY_CATEGORY_SERVICES,
+                "", TEST_USER_ID);
+    }
+
+    @Test
+    public void receiveActionSendNotification_isNonA11yCategoryService_sendNotification() {
+        mEnabledServiceList.add(mMockA11yServiceInfo);
+        mMockResolveInfo.serviceInfo = mMockServiceInfo;
+        when(mMockA11yServiceInfo.getResolveInfo()).thenReturn(mMockResolveInfo);
+        when(mMockA11yServiceInfo.getComponentName()).thenReturn(TEST_COMPONENT_NAME);
+        when(mAccessibilitySecurityPolicy.isA11yCategoryService(
+                mMockA11yServiceInfo)).thenReturn(false);
+
+        mFakeNotificationController.onReceive(mContext, createIntent(TEST_USER_ID,
+                PolicyWarningUIController.ACTION_SEND_NOTIFICATION,
+                TEST_COMPONENT_NAME.flattenToShortString()));
+
+        verify(mNotificationManager).notify(eq(TEST_COMPONENT_NAME.flattenToShortString()),
+                eq(NOTE_A11Y_VIEW_AND_CONTROL_ACCESS), any(
+                        Notification.class));
+    }
+
+    @Test
+    public void receiveActionA11ySettings_launchA11ySettingsAndDismissNotification() {
+        mFakeNotificationController.onReceive(mContext,
+                createIntent(TEST_USER_ID, PolicyWarningUIController.ACTION_A11Y_SETTINGS,
+                        TEST_COMPONENT_NAME.flattenToShortString()));
+
+        verifyLaunchA11ySettings();
+        verify(mNotificationManager).cancel(TEST_COMPONENT_NAME.flattenToShortString(),
+                NOTE_A11Y_VIEW_AND_CONTROL_ACCESS);
+        assertNotifiedSettingsEqual(TEST_USER_ID,
+                TEST_COMPONENT_NAME.flattenToShortString());
+    }
+
+    @Test
+    public void receiveActionDismissNotification_addToNotifiedSettings() {
+        mFakeNotificationController.onReceive(mContext, createIntent(TEST_USER_ID,
+                PolicyWarningUIController.ACTION_DISMISS_NOTIFICATION,
+                TEST_COMPONENT_NAME.flattenToShortString()));
+
+        assertNotifiedSettingsEqual(TEST_USER_ID,
+                TEST_COMPONENT_NAME.flattenToShortString());
+    }
+
+    @Test
+    public void onEnabledServicesChangedLocked_serviceDisabled_removedFromNotifiedSettings() {
+        final Set<ComponentName> enabledServices = new HashSet<>();
+        enabledServices.add(TEST_COMPONENT_NAME);
+        mPolicyWarningUIController.onEnabledServicesChangedLocked(TEST_USER_ID, enabledServices);
+        getInstrumentation().waitForIdleSync();
+        receiveActionDismissNotification_addToNotifiedSettings();
+
+        mPolicyWarningUIController.onEnabledServicesChangedLocked(TEST_USER_ID, new HashSet<>());
+        getInstrumentation().waitForIdleSync();
+
+        assertNotifiedSettingsEqual(TEST_USER_ID, "");
+    }
+
+    @Test
+    public void onNonA11yCategoryServiceBound_setAlarm() {
+        mPolicyWarningUIController.onNonA11yCategoryServiceBound(TEST_USER_ID, TEST_COMPONENT_NAME);
+        getInstrumentation().waitForIdleSync();
+
+        verify(mAlarmManager).set(eq(RTC_WAKEUP), anyLong(),
+                eq(PolicyWarningUIController.createPendingIntent(mContext, TEST_USER_ID,
+                        PolicyWarningUIController.ACTION_SEND_NOTIFICATION,
+                        TEST_COMPONENT_NAME.flattenToShortString())));
+    }
+
+    @Test
+    public void onNonA11yCategoryServiceUnbound_cancelAlarm() {
+        mPolicyWarningUIController.onNonA11yCategoryServiceUnbound(TEST_USER_ID,
+                TEST_COMPONENT_NAME);
+        getInstrumentation().waitForIdleSync();
+
+        verify(mAlarmManager).cancel(
+                eq(PolicyWarningUIController.createPendingIntent(mContext, TEST_USER_ID,
+                        PolicyWarningUIController.ACTION_SEND_NOTIFICATION,
+                        TEST_COMPONENT_NAME.flattenToShortString())));
+    }
+
+    private void assertNotifiedSettingsEqual(int userId, String settingString) {
+        final String notifiedServicesSetting = Settings.Secure.getStringForUser(
+                mContext.getContentResolver(),
+                Settings.Secure.NOTIFIED_NON_ACCESSIBILITY_CATEGORY_SERVICES,
+                userId);
+        assertEquals(settingString, notifiedServicesSetting);
+    }
+
+    private Intent createIntent(int userId, String action, String serviceComponentName) {
+        final Intent intent = new Intent(action);
+        intent.setPackage(mContext.getPackageName())
+                .setIdentifier(serviceComponentName)
+                .putExtra(Intent.EXTRA_USER_ID, userId);
+        return intent;
+    }
+
+    private void verifyLaunchA11ySettings() {
+        final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+        final ArgumentCaptor<UserHandle> userHandleCaptor = ArgumentCaptor.forClass(
+                UserHandle.class);
+        verify(mSpyContext).startActivityAsUser(intentCaptor.capture(),
+                any(), userHandleCaptor.capture());
+        assertThat(intentCaptor.getValue().getAction()).isEqualTo(
+                Settings.ACTION_ACCESSIBILITY_DETAILS_SETTINGS);
+        assertThat(userHandleCaptor.getValue().getIdentifier()).isEqualTo(TEST_USER_ID);
+        verify(mStatusBarManager).collapsePanels();
+    }
+
+    private class A11yTestableContext extends TestableContext {
+        A11yTestableContext(Context base) {
+            super(base);
+        }
+
+        @Override
+        public void startActivityAsUser(Intent intent, Bundle options, UserHandle user) {
+            mSpyContext.startActivityAsUser(intent, options, user);
+        }
+    }
+
+    private class FakeNotificationController extends
+            PolicyWarningUIController.NotificationController {
+        FakeNotificationController(Context context) {
+            super(context);
+        }
+
+        @Override
+        protected List<AccessibilityServiceInfo> getEnabledServiceInfos() {
+            return mEnabledServiceList;
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
index 872b955..29691fb 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
@@ -65,7 +65,6 @@
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mockito;
-import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
 import java.util.Locale;
@@ -1115,6 +1114,23 @@
     }
 
     @Test
+    public void testSetForceShowMagnifiableBounds() {
+        register(DISPLAY_0);
+
+        mFullScreenMagnificationController.setForceShowMagnifiableBounds(DISPLAY_0, true);
+
+        verify(mMockWindowManager).setForceShowMagnifiableBounds(DISPLAY_0, true);
+    }
+
+    @Test
+    public void testIsForceShowMagnifiableBounds() {
+        register(DISPLAY_0);
+        mFullScreenMagnificationController.setForceShowMagnifiableBounds(DISPLAY_0, true);
+
+        assertTrue(mFullScreenMagnificationController.isForceShowMagnifiableBounds(DISPLAY_0));
+    }
+
+    @Test
     public void testSetScale_toMagnifying_shouldNotifyActivatedState() {
         setScaleToMagnifying();
 
@@ -1142,14 +1158,11 @@
         for (int i = 0; i < DISPLAY_COUNT; i++) {
             when(mMockWindowManager.setMagnificationCallbacks(eq(i), any())).thenReturn(true);
         }
-        doAnswer(new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
-                Object[] args = invocationOnMock.getArguments();
-                Region regionArg = (Region) args[1];
-                regionArg.set(INITIAL_MAGNIFICATION_REGION);
-                return null;
-            }
+        doAnswer((Answer<Void>) invocationOnMock -> {
+            Object[] args = invocationOnMock.getArguments();
+            Region regionArg = (Region) args[1];
+            regionArg.set(INITIAL_MAGNIFICATION_REGION);
+            return null;
         }).when(mMockWindowManager).getMagnificationRegion(anyInt(), (Region) anyObject());
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
index 84c76b7..cf23197 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
@@ -25,6 +25,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
@@ -174,6 +175,23 @@
     }
 
     @Test
+    public void transitionToWindowMode_disablingWindowMode_showMagnificationButton()
+            throws RemoteException {
+        setMagnificationEnabled(MODE_WINDOW);
+        mMagnificationController.transitionMagnificationModeLocked(TEST_DISPLAY,
+                MODE_FULLSCREEN,
+                mTransitionCallBack);
+
+        mMagnificationController.transitionMagnificationModeLocked(TEST_DISPLAY,
+                MODE_WINDOW,
+                mTransitionCallBack);
+
+        mMockConnection.invokeCallbacks();
+        verify(mWindowMagnificationManager).showMagnificationButton(eq(TEST_DISPLAY),
+                eq(MODE_WINDOW));
+    }
+
+    @Test
     public void transitionToFullScreenMode_windowMagnifying_disableWindowAndEnableFullScreen()
             throws RemoteException {
         setMagnificationEnabled(MODE_WINDOW);
@@ -228,7 +246,6 @@
         verify(mTransitionCallBack).onResult(true);
     }
 
-
     @Test
     public void interruptDuringTransitionToFullScreenMode_windowMagnifying_notifyTransitionFailed()
             throws RemoteException {
@@ -365,6 +382,19 @@
                 eq(MODE_FULLSCREEN));
     }
 
+
+    @Test
+    public void onTouchInteractionChanged_fullscreenNotActivated_notShowMagnificationButton()
+            throws RemoteException {
+        setMagnificationModeSettings(MODE_FULLSCREEN);
+
+        mMagnificationController.onTouchInteractionStart(TEST_DISPLAY, MODE_FULLSCREEN);
+        mMagnificationController.onTouchInteractionEnd(TEST_DISPLAY, MODE_FULLSCREEN);
+
+        verify(mWindowMagnificationManager, never()).showMagnificationButton(eq(TEST_DISPLAY),
+                eq(MODE_FULLSCREEN));
+    }
+
     @Test
     public void onShortcutTriggered_windowModeEnabledAndCapabilitiesAll_showMagnificationButton()
             throws RemoteException {
@@ -427,6 +457,35 @@
         verify(mWindowMagnificationManager).removeMagnificationButton(eq(TEST_DISPLAY));
     }
 
+    @Test
+    public void transitionToFullScreenMode_fullscreenModeActivated_showMagnificationButton()
+            throws RemoteException {
+        setMagnificationEnabled(MODE_WINDOW);
+
+        mMagnificationController.transitionMagnificationModeLocked(TEST_DISPLAY,
+                MODE_FULLSCREEN, mTransitionCallBack);
+        mMockConnection.invokeCallbacks();
+
+        verify(mWindowMagnificationManager).showMagnificationButton(eq(TEST_DISPLAY),
+                eq(MODE_FULLSCREEN));
+    }
+
+    @Test
+    public void transitionToWindow_windowModeActivated_showMagnificationButton()
+            throws RemoteException {
+        setMagnificationEnabled(MODE_FULLSCREEN);
+
+        mMagnificationController.transitionMagnificationModeLocked(TEST_DISPLAY,
+                MODE_WINDOW, mTransitionCallBack);
+
+        verify(mScreenMagnificationController).reset(eq(TEST_DISPLAY),
+                mCallbackArgumentCaptor.capture());
+        mCallbackArgumentCaptor.getValue().onResult(true);
+        mMockConnection.invokeCallbacks();
+        verify(mWindowMagnificationManager).showMagnificationButton(eq(TEST_DISPLAY),
+                eq(MODE_WINDOW));
+    }
+
     private void setMagnificationEnabled(int mode) throws RemoteException {
 
         setMagnificationEnabled(mode, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y);
@@ -450,6 +509,8 @@
         }
         if (mode == MODE_FULLSCREEN) {
             when(mScreenMagnificationController.isMagnifying(TEST_DISPLAY)).thenReturn(true);
+            when(mScreenMagnificationController.isForceShowMagnifiableBounds(
+                    TEST_DISPLAY)).thenReturn(true);
             when(mScreenMagnificationController.getPersistedScale()).thenReturn(DEFAULT_SCALE);
             when(mScreenMagnificationController.getScale(TEST_DISPLAY)).thenReturn(DEFAULT_SCALE);
             when(mScreenMagnificationController.getCenterX(TEST_DISPLAY)).thenReturn(
@@ -457,6 +518,11 @@
             when(mScreenMagnificationController.getCenterY(TEST_DISPLAY)).thenReturn(
                     centerY);
         } else {
+            doAnswer(invocation -> {
+                when(mScreenMagnificationController.isMagnifying(TEST_DISPLAY)).thenReturn(true);
+                return null;
+            }).when(mScreenMagnificationController).setScaleAndCenter(eq(TEST_DISPLAY),
+                    eq(DEFAULT_SCALE), anyFloat(), anyFloat(), anyBoolean(), anyInt());
             mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, DEFAULT_SCALE,
                     centerX, centerY, null);
             mMockConnection.invokeCallbacks();
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java b/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java
index b5f4912..ad22cba 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java
@@ -103,12 +103,12 @@
         // Insert package1 document
         GenericDocument document1 =
                 new GenericDocument.Builder<>("uri", "schema1").setNamespace("namespace").build();
-        mAppSearchImpl.putDocument("package1", "database1", document1);
+        mAppSearchImpl.putDocument("package1", "database1", document1, /*logger=*/ null);
 
         // Insert package2 document
         GenericDocument document2 =
                 new GenericDocument.Builder<>("uri", "schema2").setNamespace("namespace").build();
-        mAppSearchImpl.putDocument("package2", "database2", document2);
+        mAppSearchImpl.putDocument("package2", "database2", document2, /*logger=*/ null);
 
         // No query filters specified, global query can retrieve all documents.
         SearchSpec searchSpec =
@@ -155,12 +155,12 @@
         // Insert package1 document
         GenericDocument document1 =
                 new GenericDocument.Builder<>("uri", "schema1").setNamespace("namespace").build();
-        mAppSearchImpl.putDocument("package1", "database1", document1);
+        mAppSearchImpl.putDocument("package1", "database1", document1, /*logger=*/ null);
 
         // Insert package2 document
         GenericDocument document2 =
                 new GenericDocument.Builder<>("uri", "schema2").setNamespace("namespace").build();
-        mAppSearchImpl.putDocument("package2", "database2", document2);
+        mAppSearchImpl.putDocument("package2", "database2", document2, /*logger=*/ null);
 
         // "package1" filter specified
         SearchSpec searchSpec =
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 c84c1cf..e0cdedd 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
@@ -416,7 +416,7 @@
                 i++) {
             GenericDocument document =
                     new GenericDocument.Builder<>("namespace", "uri" + i, "type").build();
-            mAppSearchImpl.putDocument("package", "database", document);
+            mAppSearchImpl.putDocument("package", "database", document, /*logger=*/ null);
         }
 
         // Check optimize() will release 0 docs since there is no deletion.
@@ -476,7 +476,7 @@
         // Insert document
         GenericDocument document =
                 new GenericDocument.Builder<>("namespace", "uri", "type").build();
-        mAppSearchImpl.putDocument("package", "database", document);
+        mAppSearchImpl.putDocument("package", "database", document, /*logger=*/ null);
 
         // Rewrite SearchSpec
         mAppSearchImpl.rewriteSearchSpecForPrefixesLocked(
@@ -516,11 +516,11 @@
         // Insert documents
         GenericDocument document1 =
                 new GenericDocument.Builder<>("namespace", "uri", "typeA").build();
-        mAppSearchImpl.putDocument("package", "database1", document1);
+        mAppSearchImpl.putDocument("package", "database1", document1, /*logger=*/ null);
 
         GenericDocument document2 =
                 new GenericDocument.Builder<>("namespace", "uri", "typeB").build();
-        mAppSearchImpl.putDocument("package", "database2", document2);
+        mAppSearchImpl.putDocument("package", "database2", document2, /*logger=*/ null);
 
         // Rewrite SearchSpec
         mAppSearchImpl.rewriteSearchSpecForPrefixesLocked(
@@ -560,7 +560,7 @@
         // Insert document
         GenericDocument document =
                 new GenericDocument.Builder<>("namespace", "uri", "type").build();
-        mAppSearchImpl.putDocument("package", "database", document);
+        mAppSearchImpl.putDocument("package", "database", document, /*logger=*/ null);
 
         // If 'allowedPrefixedSchemas' is empty, this returns false since there's nothing to
         // search over. Despite the searchSpecProto having schema type filters.
@@ -613,7 +613,7 @@
         // Insert package1 document
         GenericDocument document =
                 new GenericDocument.Builder<>("namespace", "uri", "schema1").build();
-        mAppSearchImpl.putDocument("package1", "database1", document);
+        mAppSearchImpl.putDocument("package1", "database1", document, /*logger=*/ null);
 
         // No query filters specified, package2 shouldn't be able to query for package1's documents.
         SearchSpec searchSpec =
@@ -624,7 +624,7 @@
 
         // Insert package2 document
         document = new GenericDocument.Builder<>("namespace", "uri", "schema2").build();
-        mAppSearchImpl.putDocument("package2", "database2", document);
+        mAppSearchImpl.putDocument("package2", "database2", document, /*logger=*/ null);
 
         // No query filters specified. package2 should only get its own documents back.
         searchResultPage = mAppSearchImpl.query("package2", "database2", "", searchSpec);
@@ -663,7 +663,7 @@
         // Insert package1 document
         GenericDocument document =
                 new GenericDocument.Builder<>("namespace", "uri", "schema1").build();
-        mAppSearchImpl.putDocument("package1", "database1", document);
+        mAppSearchImpl.putDocument("package1", "database1", document, /*logger=*/ null);
 
         // "package1" filter specified, but package2 shouldn't be able to query for package1's
         // documents.
@@ -678,7 +678,7 @@
 
         // Insert package2 document
         document = new GenericDocument.Builder<>("namespace", "uri", "schema2").build();
-        mAppSearchImpl.putDocument("package2", "database2", document);
+        mAppSearchImpl.putDocument("package2", "database2", document, /*logger=*/ null);
 
         // "package2" filter specified, package2 should only get its own documents back.
         searchSpec =
@@ -1124,7 +1124,8 @@
                     appSearchImpl.putDocument(
                             "package",
                             "database",
-                            new GenericDocument.Builder<>("namespace", "uri", "type").build());
+                            new GenericDocument.Builder<>("namespace", "uri", "type").build(),
+                            /*logger=*/ null);
                 });
 
         expectThrows(
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java
new file mode 100644
index 0000000..467ede4
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.appsearch.external.localstorage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.appsearch.AppSearchResult;
+import android.app.appsearch.AppSearchSchema;
+import android.app.appsearch.GenericDocument;
+import android.content.Context;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.server.appsearch.external.localstorage.stats.CallStats;
+import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
+import com.android.server.appsearch.proto.PutDocumentStatsProto;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.util.Collections;
+import java.util.List;
+
+public class AppSearchLoggerTest {
+    @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+    private AppSearchImpl mAppSearchImpl;
+    private TestLogger mLogger;
+
+    @Before
+    public void setUp() throws Exception {
+        Context context = ApplicationProvider.getApplicationContext();
+
+        // Give ourselves global query permissions
+        mAppSearchImpl =
+                AppSearchImpl.create(
+                        mTemporaryFolder.newFolder(),
+                        context,
+                        VisibilityStore.NO_OP_USER_ID,
+                        /*globalQuerierPackage=*/ context.getPackageName());
+        mLogger = new TestLogger();
+    }
+
+    // Test only not thread safe.
+    public class TestLogger implements AppSearchLogger {
+        @Nullable PutDocumentStats mPutDocumentStats;
+
+        @Override
+        public void logStats(@NonNull CallStats stats) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void logStats(@NonNull PutDocumentStats stats) {
+            mPutDocumentStats = stats;
+        }
+    }
+
+    @Test
+    public void testAppSearchLoggerHelper_testCopyNativeStats_putDocument() {
+        final int nativeLatencyMillis = 3;
+        final int nativeDocumentStoreLatencyMillis = 4;
+        final int nativeIndexLatencyMillis = 5;
+        final int nativeIndexMergeLatencyMillis = 6;
+        final int nativeDocumentSize = 7;
+        final int nativeNumTokensIndexed = 8;
+        final boolean nativeExceededMaxNumTokens = true;
+        PutDocumentStatsProto nativePutDocumentStats =
+                PutDocumentStatsProto.newBuilder()
+                        .setLatencyMs(nativeLatencyMillis)
+                        .setDocumentStoreLatencyMs(nativeDocumentStoreLatencyMillis)
+                        .setIndexLatencyMs(nativeIndexLatencyMillis)
+                        .setIndexMergeLatencyMs(nativeIndexMergeLatencyMillis)
+                        .setDocumentSize(nativeDocumentSize)
+                        .setTokenizationStats(
+                                PutDocumentStatsProto.TokenizationStats.newBuilder()
+                                        .setNumTokensIndexed(nativeNumTokensIndexed)
+                                        .setExceededMaxTokenNum(nativeExceededMaxNumTokens)
+                                        .build())
+                        .build();
+        PutDocumentStats.Builder pBuilder = new PutDocumentStats.Builder("packageName", "database");
+
+        AppSearchLoggerHelper.copyNativeStats(nativePutDocumentStats, pBuilder);
+
+        PutDocumentStats pStats = pBuilder.build();
+        assertThat(pStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis);
+        assertThat(pStats.getNativeDocumentStoreLatencyMillis())
+                .isEqualTo(nativeDocumentStoreLatencyMillis);
+        assertThat(pStats.getNativeIndexLatencyMillis()).isEqualTo(nativeIndexLatencyMillis);
+        assertThat(pStats.getNativeIndexMergeLatencyMillis())
+                .isEqualTo(nativeIndexMergeLatencyMillis);
+        assertThat(pStats.getNativeDocumentSizeBytes()).isEqualTo(nativeDocumentSize);
+        assertThat(pStats.getNativeNumTokensIndexed()).isEqualTo(nativeNumTokensIndexed);
+        assertThat(pStats.getNativeExceededMaxNumTokens()).isEqualTo(nativeExceededMaxNumTokens);
+    }
+
+    //
+    // Testing actual logging
+    //
+    @Test
+    public void testLoggingStats_putDocument() throws Exception {
+        // Insert schema
+        final String testPackageName = "testPackage";
+        final String testDatabase = "testDatabase";
+        List<AppSearchSchema> schemas =
+                Collections.singletonList(new AppSearchSchema.Builder("type").build());
+        mAppSearchImpl.setSchema(
+                testPackageName,
+                testDatabase,
+                schemas,
+                /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+                /*schemasPackageAccessible=*/ Collections.emptyMap(),
+                /*forceOverride=*/ false);
+        GenericDocument document =
+                new GenericDocument.Builder<>("namespace", "uri", "type").build();
+
+        mAppSearchImpl.putDocument(testPackageName, testDatabase, document, mLogger);
+
+        PutDocumentStats pStats = mLogger.mPutDocumentStats;
+        assertThat(pStats).isNotNull();
+        assertThat(pStats.getGeneralStats().getPackageName()).isEqualTo(testPackageName);
+        assertThat(pStats.getGeneralStats().getDatabase()).isEqualTo(testDatabase);
+        assertThat(pStats.getGeneralStats().getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK);
+        // The rest of native stats have been tested in testCopyNativeStats
+        assertThat(pStats.getNativeDocumentSizeBytes()).isGreaterThan(0);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java
index 4308885..8dbf249 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java
@@ -18,12 +18,14 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.app.appsearch.AppSearchResult;
+
 import org.junit.Test;
 
 public class AppSearchStatsTest {
     static final String TEST_PACKAGE_NAME = "com.google.test";
     static final String TEST_DATA_BASE = "testDataBase";
-    static final int TEST_STATUS_CODE = 2;
+    static final int TEST_STATUS_CODE = AppSearchResult.RESULT_INTERNAL_ERROR;
     static final int TEST_TOTAL_LATENCY_MILLIS = 20;
 
     @Test
@@ -40,25 +42,38 @@
         assertThat(gStats.getTotalLatencyMillis()).isEqualTo(TEST_TOTAL_LATENCY_MILLIS);
     }
 
+    /** Make sure status code is UNKNOWN if not set in {@link GeneralStats} */
+    @Test
+    public void testAppSearchStats_GeneralStats_defaultStatsCode_Unknown() {
+        final GeneralStats gStats =
+                new GeneralStats.Builder(TEST_PACKAGE_NAME, TEST_DATA_BASE)
+                        .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS)
+                        .build();
+
+        assertThat(gStats.getPackageName()).isEqualTo(TEST_PACKAGE_NAME);
+        assertThat(gStats.getDatabase()).isEqualTo(TEST_DATA_BASE);
+        assertThat(gStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_UNKNOWN_ERROR);
+        assertThat(gStats.getTotalLatencyMillis()).isEqualTo(TEST_TOTAL_LATENCY_MILLIS);
+    }
+
     @Test
     public void testAppSearchStats_CallStats() {
         final int estimatedBinderLatencyMillis = 1;
         final int numOperationsSucceeded = 2;
         final int numOperationsFailed = 3;
-
-        final GeneralStats gStats =
-                new GeneralStats.Builder(TEST_PACKAGE_NAME, TEST_DATA_BASE)
-                        .setStatusCode(TEST_STATUS_CODE)
-                        .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS)
-                        .build();
         final @CallStats.CallType int callType = CallStats.CALL_TYPE_PUT_DOCUMENTS;
-        final CallStats cStats =
-                new CallStats.Builder(gStats)
+
+        final CallStats.Builder cStatsBuilder =
+                new CallStats.Builder(TEST_PACKAGE_NAME, TEST_DATA_BASE)
                         .setCallType(callType)
                         .setEstimatedBinderLatencyMillis(estimatedBinderLatencyMillis)
                         .setNumOperationsSucceeded(numOperationsSucceeded)
-                        .setNumOperationsFailed(numOperationsFailed)
-                        .build();
+                        .setNumOperationsFailed(numOperationsFailed);
+        cStatsBuilder
+                .getGeneralStatsBuilder()
+                .setStatusCode(TEST_STATUS_CODE)
+                .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS);
+        final CallStats cStats = cStatsBuilder.build();
 
         assertThat(cStats.getGeneralStats().getPackageName()).isEqualTo(TEST_PACKAGE_NAME);
         assertThat(cStats.getGeneralStats().getDatabase()).isEqualTo(TEST_DATA_BASE);
@@ -82,15 +97,9 @@
         final int nativeIndexMergeLatencyMillis = 6;
         final int nativeDocumentSize = 7;
         final int nativeNumTokensIndexed = 8;
-        final int nativeNumTokensClipped = 9;
-
-        final GeneralStats gStats =
-                new GeneralStats.Builder(TEST_PACKAGE_NAME, TEST_DATA_BASE)
-                        .setStatusCode(TEST_STATUS_CODE)
-                        .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS)
-                        .build();
-        final PutDocumentStats pStats =
-                new PutDocumentStats.Builder(gStats)
+        final boolean nativeExceededMaxNumTokens = true;
+        final PutDocumentStats.Builder pStatsBuilder =
+                new PutDocumentStats.Builder(TEST_PACKAGE_NAME, TEST_DATA_BASE)
                         .setGenerateDocumentProtoLatencyMillis(generateDocumentProtoLatencyMillis)
                         .setRewriteDocumentTypesLatencyMillis(rewriteDocumentTypesLatencyMillis)
                         .setNativeLatencyMillis(nativeLatencyMillis)
@@ -99,8 +108,12 @@
                         .setNativeIndexMergeLatencyMillis(nativeIndexMergeLatencyMillis)
                         .setNativeDocumentSizeBytes(nativeDocumentSize)
                         .setNativeNumTokensIndexed(nativeNumTokensIndexed)
-                        .setNativeNumTokensClipped(nativeNumTokensClipped)
-                        .build();
+                        .setNativeExceededMaxNumTokens(nativeExceededMaxNumTokens);
+        pStatsBuilder
+                .getGeneralStatsBuilder()
+                .setStatusCode(TEST_STATUS_CODE)
+                .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS);
+        final PutDocumentStats pStats = pStatsBuilder.build();
 
         assertThat(pStats.getGeneralStats().getPackageName()).isEqualTo(TEST_PACKAGE_NAME);
         assertThat(pStats.getGeneralStats().getDatabase()).isEqualTo(TEST_DATA_BASE);
@@ -119,6 +132,6 @@
                 .isEqualTo(nativeIndexMergeLatencyMillis);
         assertThat(pStats.getNativeDocumentSizeBytes()).isEqualTo(nativeDocumentSize);
         assertThat(pStats.getNativeNumTokensIndexed()).isEqualTo(nativeNumTokensIndexed);
-        assertThat(pStats.getNativeNumTokensClipped()).isEqualTo(nativeNumTokensClipped);
+        assertThat(pStats.getNativeExceededMaxNumTokens()).isEqualTo(nativeExceededMaxNumTokens);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
index 7a4b901..3cbc226 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
@@ -39,6 +39,7 @@
 import android.app.trust.ITrustManager;
 import android.content.Context;
 import android.hardware.biometrics.BiometricManager.Authenticators;
+import android.hardware.biometrics.ComponentInfoInternal;
 import android.hardware.biometrics.IBiometricAuthenticator;
 import android.hardware.biometrics.IBiometricSensorReceiver;
 import android.hardware.biometrics.IBiometricServiceReceiver;
@@ -150,7 +151,8 @@
                     eq(userId),
                     eq(mSensorReceiver),
                     eq(TEST_PACKAGE),
-                    eq(sensor.getCookie()));
+                    eq(sensor.getCookie()),
+                    anyBoolean() /* allowBackgroundAuthentication */);
         }
 
         final int cookie1 = session.mPreAuthInfo.eligibleSensors.get(0).getCookie();
@@ -292,9 +294,18 @@
             }
         });
 
+        final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
+        componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */,
+                "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */,
+                "00000001" /* serialNumber */, "" /* softwareVersion */));
+        componentInfo.add(new ComponentInfoInternal("matchingAlgorithm" /* componentId */,
+                "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */,
+                "vendor/version/revision" /* softwareVersion */));
+
         mFingerprintSensorProps.add(new FingerprintSensorPropertiesInternal(id,
                 SensorProperties.STRENGTH_STRONG,
                 5 /* maxEnrollmentsPerUser */,
+                componentInfo,
                 type,
                 false /* resetLockoutRequiresHardwareAuthToken */));
     }
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index 0c95e05..abc8737 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -456,7 +456,8 @@
                 anyInt() /* userId */,
                 any(IBiometricSensorReceiver.class),
                 anyString() /* opPackageName */,
-                cookieCaptor.capture() /* cookie */);
+                cookieCaptor.capture() /* cookie */,
+                anyBoolean() /* allowBackgroundAuthentication */);
 
         // onReadyForAuthentication, mCurrentAuthSession state OK
         mBiometricService.mImpl.onReadyForAuthentication(cookieCaptor.getValue());
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 77a39d8..576f9c2 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -4016,6 +4016,27 @@
     }
 
     @Test
+    public void testUpdateNetworkPreferenceOnStartOnStopUser() throws Exception {
+        dpms.handleStartUser(CALLER_USER_HANDLE);
+        // TODO(b/178655595)
+        // verify(getServices().connectivityManager, times(1)).setNetworkPreferenceForUser(
+        //         any(UserHandle.class),
+        //         anyInt(),
+        //         any(Executor.class),
+        //         any(Runnable.class)
+        //);
+
+        dpms.handleStopUser(CALLER_USER_HANDLE);
+        // TODO(b/178655595)
+        // verify(getServices().connectivityManager, times(1)).setNetworkPreferenceForUser(
+        //         any(UserHandle.class),
+        //         eq(ConnectivityManager.USER_PREFERENCE_SYSTEM_DEFAULT),
+        //         any(Executor.class),
+        //         any(Runnable.class)
+        //);
+    }
+
+    @Test
     public void testGetSetNetworkSlicing() throws Exception {
         assertExpectException(SecurityException.class, null,
                 () -> dpm.setNetworkSlicingEnabled(false));
@@ -4023,20 +4044,26 @@
         assertExpectException(SecurityException.class, null,
                 () -> dpm.isNetworkSlicingEnabled());
 
-        assertExpectException(SecurityException.class, null,
-                () -> dpm.isNetworkSlicingEnabledForUser(UserHandle.of(CALLER_USER_HANDLE)));
-
-        mContext.callerPermissions.add(permission.READ_NETWORK_DEVICE_CONFIG);
-        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
-        try {
-            dpm.isNetworkSlicingEnabledForUser(UserHandle.of(CALLER_USER_HANDLE));
-        } catch (SecurityException se) {
-            fail("Threw SecurityException with right permission");
-        }
-
         setupProfileOwner();
         dpm.setNetworkSlicingEnabled(false);
         assertThat(dpm.isNetworkSlicingEnabled()).isFalse();
+        // TODO(b/178655595)
+        // verify(getServices().connectivityManager, times(1)).setNetworkPreferenceForUser(
+        //         any(UserHandle.class),
+        //         eq(ConnectivityManager.USER_PREFERENCE_SYSTEM_DEFAULT),
+        //         any(Executor.class),
+        //         any(Runnable.class)
+        //);
+
+        dpm.setNetworkSlicingEnabled(true);
+        assertThat(dpm.isNetworkSlicingEnabled()).isTrue();
+        // TODO(b/178655595)
+        // verify(getServices().connectivityManager, times(1)).setNetworkPreferenceForUser(
+        //         any(UserHandle.class),
+        //         eq(ConnectivityManager.USER_PREFERENCE_ENTERPRISE),
+        //         any(Executor.class),
+        //         any(Runnable.class)
+        //);
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 6068fdf..2fcc021 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -224,6 +224,8 @@
                 return mMockSystemServices.accountManager;
             case Context.TELEPHONY_SERVICE:
                 return mMockSystemServices.telephonyManager;
+            case Context.CONNECTIVITY_SERVICE:
+                return mMockSystemServices.connectivityManager;
             case Context.APP_OPS_SERVICE:
                 return mMockSystemServices.appOpsManager;
             case Context.CROSS_PROFILE_APPS_SERVICE:
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index f6dee38..9cc0572 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -47,6 +47,7 @@
 import android.database.Cursor;
 import android.hardware.usb.UsbManager;
 import android.media.IAudioService;
+import android.net.ConnectivityManager;
 import android.net.IIpConnectivityMetrics;
 import android.net.Uri;
 import android.net.wifi.WifiManager;
@@ -114,6 +115,7 @@
     public final SettingsForMock settings;
     public final MockContentResolver contentResolver;
     public final TelephonyManager telephonyManager;
+    public final ConnectivityManager connectivityManager;
     public final AccountManager accountManager;
     public final AlarmManager alarmManager;
     public final KeyChain.KeyChainConnection keyChainConnection;
@@ -159,6 +161,7 @@
         wifiManager = mock(WifiManager.class);
         settings = mock(SettingsForMock.class);
         telephonyManager = mock(TelephonyManager.class);
+        connectivityManager = mock(ConnectivityManager.class);
         accountManager = mock(AccountManager.class);
         alarmManager = mock(AlarmManager.class);
         keyChainConnection = mock(KeyChain.KeyChainConnection.class, RETURNS_DEEP_STUBS);
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
index bc86d1d..4295172 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -93,7 +93,9 @@
     private static final long SHORT_DEFAULT_DISPLAY_TIMEOUT_MILLIS = 10;
     private static final String VIRTUAL_DISPLAY_NAME = "Test Virtual Display";
     private static final String PACKAGE_NAME = "com.android.frameworks.servicestests";
-
+    private static final long ALL_DISPLAY_EVENTS = DisplayManager.EVENT_FLAG_DISPLAY_ADDED
+                    | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
+                    | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED;
     @Rule
     public TestRule compatChangeRule = new PlatformCompatChangeRule();
 
@@ -355,29 +357,13 @@
 
         // Find the display id of the added FakeDisplayDevice
         DisplayManagerService.BinderService bs = displayManager.new BinderService();
-        final int[] displayIds = bs.getDisplayIds();
-        assertTrue(displayIds.length > 0);
-        int displayId = Display.INVALID_DISPLAY;
-        for (int i = 0; i < displayIds.length; i++) {
-            DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayIds[i]);
-            if (displayDeviceInfo.equals(ddi)) {
-                displayId = displayIds[i];
-                break;
-            }
-        }
-        assertFalse(displayId == Display.INVALID_DISPLAY);
-
+        int displayId = getDisplayIdForDisplayDevice(displayManager, bs, displayDevice);
         // Setup override DisplayInfo
         DisplayInfo overrideInfo = bs.getDisplayInfo(displayId);
         displayManager.setDisplayInfoOverrideFromWindowManagerInternal(displayId, overrideInfo);
 
-        Handler handler = displayManager.getDisplayHandler();
-        handler.runWithScissors(() -> {
-        }, 0 /* now */);
-
-        // register display listener callback
-        FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback(displayId);
-        bs.registerCallback(callback);
+        FakeDisplayManagerCallback callback = registerDisplayListenerCallback(
+                displayManager, bs, displayDevice);
 
         // Simulate DisplayDevice change
         DisplayDeviceInfo displayDeviceInfo2 = new DisplayDeviceInfo();
@@ -387,9 +373,9 @@
         displayManager.getDisplayDeviceRepository()
                 .onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED);
 
-        handler.runWithScissors(() -> {
-        }, 0 /* now */);
-        assertTrue(callback.mCalled);
+        Handler handler = displayManager.getDisplayHandler();
+        waitForIdleHandler(handler);
+        assertTrue(callback.mDisplayChangedCalled);
     }
 
     /**
@@ -400,7 +386,7 @@
         DisplayManagerService displayManager =
                 new DisplayManagerService(mContext, mShortMockedInjector);
         Handler handler = displayManager.getDisplayHandler();
-        handler.runWithScissors(() -> {}, 0 /* now */);
+        waitForIdleHandler(handler);
 
         try {
             displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
@@ -616,7 +602,7 @@
     }
 
     /**
-     * Tests that there should be a display change notification if the frame rate overrides
+     * Tests that there is a display change notification if the frame rate override
      * list is updated.
      */
     @Test
@@ -637,7 +623,7 @@
                 new DisplayEventReceiver.FrameRateOverride[]{
                         new DisplayEventReceiver.FrameRateOverride(myUid, 30f),
                 });
-        assertTrue(callback.mCalled);
+        assertTrue(callback.mDisplayChangedCalled);
         callback.clear();
 
         updateFrameRateOverride(displayManager, displayDevice,
@@ -645,7 +631,7 @@
                         new DisplayEventReceiver.FrameRateOverride(myUid, 30f),
                         new DisplayEventReceiver.FrameRateOverride(1234, 30f),
                 });
-        assertFalse(callback.mCalled);
+        assertFalse(callback.mDisplayChangedCalled);
 
         updateFrameRateOverride(displayManager, displayDevice,
                 new DisplayEventReceiver.FrameRateOverride[]{
@@ -653,7 +639,7 @@
                         new DisplayEventReceiver.FrameRateOverride(1234, 30f),
                         new DisplayEventReceiver.FrameRateOverride(5678, 30f),
                 });
-        assertTrue(callback.mCalled);
+        assertTrue(callback.mDisplayChangedCalled);
         callback.clear();
 
         updateFrameRateOverride(displayManager, displayDevice,
@@ -661,14 +647,14 @@
                         new DisplayEventReceiver.FrameRateOverride(1234, 30f),
                         new DisplayEventReceiver.FrameRateOverride(5678, 30f),
                 });
-        assertTrue(callback.mCalled);
+        assertTrue(callback.mDisplayChangedCalled);
         callback.clear();
 
         updateFrameRateOverride(displayManager, displayDevice,
                 new DisplayEventReceiver.FrameRateOverride[]{
                         new DisplayEventReceiver.FrameRateOverride(5678, 30f),
                 });
-        assertFalse(callback.mCalled);
+        assertFalse(callback.mDisplayChangedCalled);
     }
 
     /**
@@ -760,6 +746,136 @@
                 /*compatChangeEnabled*/  true);
     }
 
+    /**
+     * Tests that EVENT_DISPLAY_ADDED is sent when a display is added.
+     */
+    @Test
+    public void testShouldNotifyDisplayAdded_WhenNewDisplayDeviceIsAdded() {
+        DisplayManagerService displayManager =
+                new DisplayManagerService(mContext, mShortMockedInjector);
+        DisplayManagerService.BinderService displayManagerBinderService =
+                displayManager.new BinderService();
+
+        Handler handler = displayManager.getDisplayHandler();
+        waitForIdleHandler(handler);
+
+        // register display listener callback
+        FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
+        displayManagerBinderService.registerCallbackWithEventMask(callback, ALL_DISPLAY_EVENTS);
+
+        waitForIdleHandler(handler);
+
+        createFakeDisplayDevice(displayManager, new float[]{60f});
+
+        waitForIdleHandler(handler);
+
+        assertFalse(callback.mDisplayChangedCalled);
+        assertFalse(callback.mDisplayRemovedCalled);
+        assertTrue(callback.mDisplayAddedCalled);
+    }
+
+    /**
+     * Tests that EVENT_DISPLAY_ADDED is not sent when a display is added and the
+     * client has a callback which is not subscribed to this event type.
+     */
+    @Test
+    public void testShouldNotNotifyDisplayAdded_WhenClientIsNotSubscribed() {
+        DisplayManagerService displayManager =
+                new DisplayManagerService(mContext, mShortMockedInjector);
+        DisplayManagerService.BinderService displayManagerBinderService =
+                displayManager.new BinderService();
+
+        Handler handler = displayManager.getDisplayHandler();
+        waitForIdleHandler(handler);
+
+        // register display listener callback
+        FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
+        long allEventsExceptDisplayAdded = ALL_DISPLAY_EVENTS
+                & ~DisplayManager.EVENT_FLAG_DISPLAY_ADDED;
+        displayManagerBinderService.registerCallbackWithEventMask(callback,
+                allEventsExceptDisplayAdded);
+
+        waitForIdleHandler(handler);
+
+        createFakeDisplayDevice(displayManager, new float[]{60f});
+
+        waitForIdleHandler(handler);
+
+        assertFalse(callback.mDisplayChangedCalled);
+        assertFalse(callback.mDisplayRemovedCalled);
+        assertFalse(callback.mDisplayAddedCalled);
+    }
+
+    /**
+     * Tests that EVENT_DISPLAY_REMOVED is sent when a display is removed.
+     */
+    @Test
+    public void testShouldNotifyDisplayRemoved_WhenDisplayDeviceIsRemoved() {
+        DisplayManagerService displayManager =
+                new DisplayManagerService(mContext, mShortMockedInjector);
+        DisplayManagerService.BinderService displayManagerBinderService =
+                displayManager.new BinderService();
+
+        Handler handler = displayManager.getDisplayHandler();
+        waitForIdleHandler(handler);
+
+        FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager,
+                new float[]{60f});
+
+        waitForIdleHandler(handler);
+
+        FakeDisplayManagerCallback callback = registerDisplayListenerCallback(
+                displayManager, displayManagerBinderService, displayDevice);
+
+        waitForIdleHandler(handler);
+
+        displayManager.getDisplayDeviceRepository()
+                .onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED);
+
+        waitForIdleHandler(handler);
+
+        assertFalse(callback.mDisplayChangedCalled);
+        assertTrue(callback.mDisplayRemovedCalled);
+        assertFalse(callback.mDisplayAddedCalled);
+    }
+
+    /**
+     * Tests that EVENT_DISPLAY_REMOVED is not sent when a display is added and the
+     * client has a callback which is not subscribed to this event type.
+     */
+    @Test
+    public void testShouldNotNotifyDisplayRemoved_WhenClientIsNotSubscribed() {
+        DisplayManagerService displayManager =
+                new DisplayManagerService(mContext, mShortMockedInjector);
+        DisplayManagerService.BinderService displayManagerBinderService =
+                displayManager.new BinderService();
+
+        Handler handler = displayManager.getDisplayHandler();
+        waitForIdleHandler(handler);
+
+        FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager,
+                new float[]{60f});
+
+        waitForIdleHandler(handler);
+
+        FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
+        long allEventsExceptDisplayRemoved = ALL_DISPLAY_EVENTS
+                & ~DisplayManager.EVENT_FLAG_DISPLAY_REMOVED;
+        displayManagerBinderService.registerCallbackWithEventMask(callback,
+                allEventsExceptDisplayRemoved);
+
+        waitForIdleHandler(handler);
+
+        displayManager.getDisplayDeviceRepository()
+                .onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED);
+
+        waitForIdleHandler(handler);
+
+        assertFalse(callback.mDisplayChangedCalled);
+        assertFalse(callback.mDisplayRemovedCalled);
+        assertFalse(callback.mDisplayAddedCalled);
+    }
+
     private void testDisplayInfoFrameRateOverrideModeCompat(boolean compatChangeEnabled)
             throws Exception {
         DisplayManagerService displayManager =
@@ -879,8 +995,7 @@
         displayManager.getDisplayDeviceRepository()
                 .onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED);
         Handler handler = displayManager.getDisplayHandler();
-        handler.runWithScissors(() -> {
-        }, 0 /* now */);
+        waitForIdleHandler(handler);
     }
 
     private void updateFrameRateOverride(DisplayManagerService displayManager,
@@ -906,18 +1021,15 @@
             DisplayManagerService.BinderService displayManagerBinderService,
             FakeDisplayDevice displayDevice) {
         // Find the display id of the added FakeDisplayDevice
-        DisplayDeviceInfo displayDeviceInfo = displayDevice.getDisplayDeviceInfoLocked();
-
         int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
                 displayDevice);
 
         Handler handler = displayManager.getDisplayHandler();
-        handler.runWithScissors(() -> {
-        }, 0 /* now */);
+        waitForIdleHandler(handler);
 
         // register display listener callback
         FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback(displayId);
-        displayManagerBinderService.registerCallback(callback);
+        displayManagerBinderService.registerCallbackWithEventMask(callback, ALL_DISPLAY_EVENTS);
         return callback;
     }
 
@@ -951,6 +1063,10 @@
         // Would prefer to call displayManager.onStart() directly here but it performs binderService
         // registration which triggers security exceptions when running from a test.
         handler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS);
+        waitForIdleHandler(handler);
+    }
+
+    private void waitForIdleHandler(Handler handler) {
         waitForIdleHandler(handler, Duration.ofSeconds(1));
     }
 
@@ -971,21 +1087,41 @@
 
     private class FakeDisplayManagerCallback extends IDisplayManagerCallback.Stub {
         int mDisplayId;
-        boolean mCalled = false;
+        boolean mDisplayAddedCalled = false;
+        boolean mDisplayChangedCalled = false;
+        boolean mDisplayRemovedCalled = false;
 
         FakeDisplayManagerCallback(int displayId) {
             mDisplayId = displayId;
         }
 
+        FakeDisplayManagerCallback() {
+            mDisplayId = -1;
+        }
+
         @Override
         public void onDisplayEvent(int displayId, int event) {
-            if (displayId == mDisplayId && event == DisplayManagerGlobal.EVENT_DISPLAY_CHANGED) {
-                mCalled = true;
+            if (mDisplayId != -1 && displayId != mDisplayId) {
+                return;
+            }
+
+            if (event == DisplayManagerGlobal.EVENT_DISPLAY_ADDED) {
+                mDisplayAddedCalled = true;
+            }
+
+            if (event == DisplayManagerGlobal.EVENT_DISPLAY_CHANGED) {
+                mDisplayChangedCalled = true;
+            }
+
+            if (event == DisplayManagerGlobal.EVENT_DISPLAY_REMOVED) {
+                mDisplayRemovedCalled = true;
             }
         }
 
         public void clear() {
-            mCalled = false;
+            mDisplayAddedCalled = false;
+            mDisplayChangedCalled = false;
+            mDisplayRemovedCalled = false;
         }
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java
index 0784b7a..415e635 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleIndexingControllerTest.java
@@ -25,6 +25,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.testng.Assert.assertThrows;
+
 import android.content.integrity.AppInstallMetadata;
 
 import org.junit.Test;
@@ -163,6 +165,22 @@
                         new RuleIndexRange(900, 945));
     }
 
+    @Test
+    public void verifyIndexingFileIsCorrupt() throws IOException {
+        byte[] stringBytes =
+                getBytes(
+                        getKeyValueString(START_INDEXING_KEY, 100)
+                                + getKeyValueString("ccc", 200)
+                                + getKeyValueString(END_INDEXING_KEY, 300)
+                                + getKeyValueString(END_INDEXING_KEY, 900));
+        ByteBuffer rule = ByteBuffer.allocate(stringBytes.length);
+        rule.put(stringBytes);
+        InputStream inputStream = new ByteArrayInputStream(rule.array());
+
+        assertThrows(IllegalStateException.class,
+                () -> new RuleIndexingController(inputStream));
+    }
+
     private static InputStream obtainDefaultIndexingMapForTest() {
         byte[] stringBytes =
                 getBytes(
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java
index 55cd772..94e67d1 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java
@@ -23,15 +23,14 @@
 
 import android.content.om.OverlayIdentifier;
 import android.content.om.OverlayInfo;
-import android.util.ArraySet;
 
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.util.Arrays;
-import java.util.function.BiConsumer;
+import java.util.Set;
+import java.util.function.Consumer;
 
 @RunWith(AndroidJUnit4.class)
 public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceImplTestsBase {
@@ -45,51 +44,47 @@
     private static final OverlayIdentifier IDENTIFIER2 = new OverlayIdentifier(OVERLAY2);
 
     @Test
-    public void testUpdateOverlaysForUser() {
+    public void alwaysInitializeAllPackages() {
         final OverlayManagerServiceImpl impl = getImpl();
         final String otherTarget = "some.other.target";
         addPackage(target(TARGET), USER);
         addPackage(target(otherTarget), USER);
         addPackage(overlay(OVERLAY, TARGET), USER);
 
-        // do nothing, expect no change
-        final ArraySet<PackageAndUser> a = impl.updateOverlaysForUser(USER);
-        assertEquals(3, a.size());
-        assertTrue(a.containsAll(Arrays.asList(
-                new PackageAndUser(TARGET, USER),
-                new PackageAndUser(otherTarget, USER),
-                new PackageAndUser(OVERLAY, USER))));
+        final Set<PackageAndUser> allPackages =
+                Set.of(new PackageAndUser(TARGET, USER),
+                        new PackageAndUser(otherTarget, USER),
+                        new PackageAndUser(OVERLAY, USER));
 
-        final ArraySet<PackageAndUser> b = impl.updateOverlaysForUser(USER);
-        assertEquals(3, b.size());
-        assertTrue(b.containsAll(Arrays.asList(
-                new PackageAndUser(TARGET, USER),
-                new PackageAndUser(otherTarget, USER),
-                new PackageAndUser(OVERLAY, USER))));
+        assertEquals(allPackages, impl.updateOverlaysForUser(USER));
+        assertEquals(allPackages, impl.updateOverlaysForUser(USER));
     }
 
     @Test
-    public void testImmutableEnabledChange() throws Exception {
+    public void testImmutableEnabledChange() {
         final OverlayManagerServiceImpl impl = getImpl();
-        installPackage(target(TARGET), USER);
-        installPackage(overlay(OVERLAY, TARGET), USER);
+        addPackage(target(TARGET), USER);
+        addPackage(overlay(OVERLAY, TARGET), USER);
 
-        configureSystemOverlay(OVERLAY, false /* mutable */, false /* enabled */, 0 /* priority */);
-        impl.updateOverlaysForUser(USER);
+        final Set<PackageAndUser> allPackages =
+                Set.of(new PackageAndUser(TARGET, USER), new PackageAndUser(OVERLAY, USER));
+
+        configureSystemOverlay(OVERLAY, ConfigState.IMMUTABLE_DISABLED, 0 /* priority */);
+        assertEquals(allPackages, impl.updateOverlaysForUser(USER));
         final OverlayInfo o1 = impl.getOverlayInfo(IDENTIFIER, USER);
         assertNotNull(o1);
         assertFalse(o1.isEnabled());
         assertFalse(o1.isMutable);
 
-        configureSystemOverlay(OVERLAY, false /* mutable */, true /* enabled */, 0 /* priority */);
-        impl.updateOverlaysForUser(USER);
+        configureSystemOverlay(OVERLAY, ConfigState.IMMUTABLE_ENABLED, 0 /* priority */);
+        assertEquals(allPackages, impl.updateOverlaysForUser(USER));
         final OverlayInfo o2 = impl.getOverlayInfo(IDENTIFIER, USER);
         assertNotNull(o2);
         assertTrue(o2.isEnabled());
         assertFalse(o2.isMutable);
 
-        configureSystemOverlay(OVERLAY, false /* mutable */, false /* enabled */, 0 /* priority */);
-        impl.updateOverlaysForUser(USER);
+        configureSystemOverlay(OVERLAY, ConfigState.IMMUTABLE_DISABLED, 0 /* priority */);
+        assertEquals(allPackages, impl.updateOverlaysForUser(USER));
         final OverlayInfo o3 = impl.getOverlayInfo(IDENTIFIER, USER);
         assertNotNull(o3);
         assertFalse(o3.isEnabled());
@@ -97,27 +92,30 @@
     }
 
     @Test
-    public void testMutableEnabledChangeHasNoEffect() throws Exception {
+    public void testMutableEnabledChangeHasNoEffect() {
         final OverlayManagerServiceImpl impl = getImpl();
-        installPackage(target(TARGET), USER);
-        installPackage(overlay(OVERLAY, TARGET), USER);
-        configureSystemOverlay(OVERLAY, true /* mutable */, false /* enabled */, 0 /* priority */);
+        addPackage(target(TARGET), USER);
+        addPackage(overlay(OVERLAY, TARGET), USER);
+        configureSystemOverlay(OVERLAY, ConfigState.MUTABLE_DISABLED, 0 /* priority */);
 
-        impl.updateOverlaysForUser(USER);
+        final Set<PackageAndUser> allPackages =
+                Set.of(new PackageAndUser(TARGET, USER), new PackageAndUser(OVERLAY, USER));
+
+        assertEquals(allPackages, impl.updateOverlaysForUser(USER));
         final OverlayInfo o1 = impl.getOverlayInfo(IDENTIFIER, USER);
         assertNotNull(o1);
         assertFalse(o1.isEnabled());
         assertTrue(o1.isMutable);
 
-        configureSystemOverlay(OVERLAY, true /* mutable */, true /* enabled */, 0 /* priority */);
-        impl.updateOverlaysForUser(USER);
+        configureSystemOverlay(OVERLAY, ConfigState.MUTABLE_ENABLED, 0 /* priority */);
+        assertEquals(allPackages, impl.updateOverlaysForUser(USER));
         final OverlayInfo o2 = impl.getOverlayInfo(IDENTIFIER, USER);
         assertNotNull(o2);
         assertFalse(o2.isEnabled());
         assertTrue(o2.isMutable);
 
-        configureSystemOverlay(OVERLAY, true /* mutable */, false /* enabled */, 0 /* priority */);
-        impl.updateOverlaysForUser(USER);
+        configureSystemOverlay(OVERLAY, ConfigState.MUTABLE_DISABLED, 0 /* priority */);
+        assertEquals(allPackages, impl.updateOverlaysForUser(USER));
         final OverlayInfo o3 = impl.getOverlayInfo(IDENTIFIER, USER);
         assertNotNull(o3);
         assertFalse(o3.isEnabled());
@@ -125,59 +123,68 @@
     }
 
     @Test
-    public void testMutableEnabledToImmutableEnabled() throws Exception {
+    public void testMutableEnabledToImmutableEnabled() {
         final OverlayManagerServiceImpl impl = getImpl();
-        installPackage(target(TARGET), USER);
-        installPackage(overlay(OVERLAY, TARGET), USER);
+        addPackage(target(TARGET), USER);
+        addPackage(overlay(OVERLAY, TARGET), USER);
 
-        final BiConsumer<Boolean, Boolean> setOverlay = (mutable, enabled) -> {
-            configureSystemOverlay(OVERLAY, mutable, enabled, 0 /* priority */);
-            impl.updateOverlaysForUser(USER);
+        final Set<PackageAndUser> allPackages =
+                Set.of(new PackageAndUser(TARGET, USER), new PackageAndUser(OVERLAY, USER));
+
+        final Consumer<ConfigState> setOverlay = (state -> {
+            configureSystemOverlay(OVERLAY, state, 0 /* priority */);
+            assertEquals(allPackages, impl.updateOverlaysForUser(USER));
             final OverlayInfo o = impl.getOverlayInfo(IDENTIFIER, USER);
             assertNotNull(o);
-            assertEquals(enabled, o.isEnabled());
-            assertEquals(mutable, o.isMutable);
-        };
+            assertEquals(o.isEnabled(), state == ConfigState.IMMUTABLE_ENABLED
+                    || state == ConfigState.MUTABLE_ENABLED);
+            assertEquals(o.isMutable, state == ConfigState.MUTABLE_DISABLED
+                    || state == ConfigState.MUTABLE_ENABLED);
+        });
 
         // Immutable/enabled -> mutable/enabled
-        setOverlay.accept(false /* mutable */, true /* enabled */);
-        setOverlay.accept(true /* mutable */, true /* enabled */);
+        setOverlay.accept(ConfigState.IMMUTABLE_ENABLED);
+        setOverlay.accept(ConfigState.MUTABLE_ENABLED);
 
         // Mutable/enabled -> immutable/enabled
-        setOverlay.accept(false /* mutable */, true /* enabled */);
+        setOverlay.accept(ConfigState.IMMUTABLE_ENABLED);
 
         // Immutable/enabled -> mutable/disabled
-        setOverlay.accept(true /* mutable */, false /* enabled */);
+        setOverlay.accept(ConfigState.MUTABLE_DISABLED);
 
         // Mutable/disabled -> immutable/enabled
-        setOverlay.accept(false /* mutable */, true /* enabled */);
+        setOverlay.accept(ConfigState.IMMUTABLE_ENABLED);
 
         // Immutable/enabled -> immutable/disabled
-        setOverlay.accept(false /* mutable */, false /* enabled */);
+        setOverlay.accept(ConfigState.IMMUTABLE_DISABLED);
 
         // Immutable/disabled -> mutable/enabled
-        setOverlay.accept(true /* mutable */, true /* enabled */);
+        setOverlay.accept(ConfigState.MUTABLE_ENABLED);
 
         // Mutable/enabled -> immutable/disabled
-        setOverlay.accept(false /* mutable */, false /* enabled */);
+        setOverlay.accept(ConfigState.IMMUTABLE_DISABLED);
 
         // Immutable/disabled -> mutable/disabled
-        setOverlay.accept(true /* mutable */, false /* enabled */);
+        setOverlay.accept(ConfigState.MUTABLE_DISABLED);
 
         // Mutable/disabled -> immutable/disabled
-        setOverlay.accept(false /* mutable */, false /* enabled */);
+        setOverlay.accept(ConfigState.IMMUTABLE_DISABLED);
     }
 
     @Test
     public void testMutablePriorityChange() throws Exception {
         final OverlayManagerServiceImpl impl = getImpl();
-        installPackage(target(TARGET), USER);
-        installPackage(overlay(OVERLAY, TARGET), USER);
-        installPackage(overlay(OVERLAY2, TARGET), USER);
-        configureSystemOverlay(OVERLAY, true /* mutable */, false /* enabled */, 0 /* priority */);
-        configureSystemOverlay(OVERLAY2, true /* mutable */, false /* enabled */, 1 /* priority */);
-        impl.updateOverlaysForUser(USER);
+        addPackage(target(TARGET), USER);
+        addPackage(overlay(OVERLAY, TARGET), USER);
+        addPackage(overlay(OVERLAY2, TARGET), USER);
+        configureSystemOverlay(OVERLAY, ConfigState.MUTABLE_DISABLED, 0 /* priority */);
+        configureSystemOverlay(OVERLAY2, ConfigState.MUTABLE_DISABLED, 1 /* priority */);
 
+        final Set<PackageAndUser> allPackages =
+                Set.of(new PackageAndUser(TARGET, USER), new PackageAndUser(OVERLAY, USER),
+                        new PackageAndUser(OVERLAY2, USER));
+
+        assertEquals(allPackages, impl.updateOverlaysForUser(USER));
         final OverlayInfo o1 = impl.getOverlayInfo(IDENTIFIER, USER);
         assertNotNull(o1);
         assertEquals(0, o1.priority);
@@ -193,10 +200,9 @@
         impl.setEnabled(IDENTIFIER, true, USER);
 
         // Reorder the overlays
-        configureSystemOverlay(OVERLAY, true /* mutable */, false /* enabled */, 1 /* priority */);
-        configureSystemOverlay(OVERLAY2, true /* mutable */, false /* enabled */, 0 /* priority */);
-        impl.updateOverlaysForUser(USER);
-
+        configureSystemOverlay(OVERLAY, ConfigState.MUTABLE_DISABLED, 1 /* priority */);
+        configureSystemOverlay(OVERLAY2, ConfigState.MUTABLE_DISABLED, 0 /* priority */);
+        assertEquals(allPackages, impl.updateOverlaysForUser(USER));
         final OverlayInfo o3 = impl.getOverlayInfo(IDENTIFIER, USER);
         assertNotNull(o3);
         assertEquals(1, o3.priority);
@@ -211,13 +217,17 @@
     @Test
     public void testImmutablePriorityChange() throws Exception {
         final OverlayManagerServiceImpl impl = getImpl();
-        installPackage(target(TARGET), USER);
-        installPackage(overlay(OVERLAY, TARGET), USER);
-        installPackage(overlay(OVERLAY2, TARGET), USER);
-        configureSystemOverlay(OVERLAY, false /* mutable */, true /* enabled */, 0 /* priority */);
-        configureSystemOverlay(OVERLAY2, false /* mutable */, true /* enabled */, 1 /* priority */);
-        impl.updateOverlaysForUser(USER);
+        addPackage(target(TARGET), USER);
+        addPackage(overlay(OVERLAY, TARGET), USER);
+        addPackage(overlay(OVERLAY2, TARGET), USER);
+        configureSystemOverlay(OVERLAY, ConfigState.IMMUTABLE_ENABLED, 0 /* priority */);
+        configureSystemOverlay(OVERLAY2, ConfigState.IMMUTABLE_ENABLED, 1 /* priority */);
 
+        final Set<PackageAndUser> allPackages =
+                Set.of(new PackageAndUser(TARGET, USER), new PackageAndUser(OVERLAY, USER),
+                        new PackageAndUser(OVERLAY2, USER));
+
+        assertEquals(allPackages, impl.updateOverlaysForUser(USER));
         final OverlayInfo o1 = impl.getOverlayInfo(IDENTIFIER, USER);
         assertNotNull(o1);
         assertEquals(0, o1.priority);
@@ -229,10 +239,9 @@
         assertTrue(o2.isEnabled());
 
         // Reorder the overlays
-        configureSystemOverlay(OVERLAY, false /* mutable */, true /* enabled */, 1 /* priority */);
-        configureSystemOverlay(OVERLAY2, false /* mutable */, true /* enabled */, 0 /* priority */);
-        impl.updateOverlaysForUser(USER);
-
+        configureSystemOverlay(OVERLAY, ConfigState.IMMUTABLE_ENABLED, 1 /* priority */);
+        configureSystemOverlay(OVERLAY2, ConfigState.IMMUTABLE_ENABLED, 0 /* priority */);
+        assertEquals(allPackages, impl.updateOverlaysForUser(USER));
         final OverlayInfo o3 = impl.getOverlayInfo(IDENTIFIER, USER);
         assertNotNull(o3);
         assertEquals(1, o3.priority);
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
index 45f82a3..f69141d 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
@@ -65,7 +65,8 @@
 
     @Test
     public void testGetOverlayInfo() throws Exception {
-        installPackage(overlay(OVERLAY, TARGET), USER);
+        installAndAssert(overlay(OVERLAY, TARGET), USER,
+                Set.of(new PackageAndUser(OVERLAY, USER), new PackageAndUser(TARGET, USER)));
 
         final OverlayManagerServiceImpl impl = getImpl();
         final OverlayInfo oi = impl.getOverlayInfo(IDENTIFIER, USER);
@@ -77,9 +78,12 @@
 
     @Test
     public void testGetOverlayInfosForTarget() throws Exception {
-        installPackage(overlay(OVERLAY, TARGET), USER);
-        installPackage(overlay(OVERLAY2, TARGET), USER);
-        installPackage(overlay(OVERLAY3, TARGET), USER2);
+        installAndAssert(overlay(OVERLAY, TARGET), USER,
+                Set.of(new PackageAndUser(OVERLAY, USER), new PackageAndUser(TARGET, USER)));
+        installAndAssert(overlay(OVERLAY2, TARGET), USER,
+                Set.of(new PackageAndUser(OVERLAY2, USER), new PackageAndUser(TARGET, USER)));
+        installAndAssert(overlay(OVERLAY3, TARGET), USER2,
+                Set.of(new PackageAndUser(OVERLAY3, USER2), new PackageAndUser(TARGET, USER2)));
 
         final OverlayManagerServiceImpl impl = getImpl();
         final List<OverlayInfo> ois = impl.getOverlayInfosForTarget(TARGET, USER);
@@ -102,10 +106,14 @@
 
     @Test
     public void testGetOverlayInfosForUser() throws Exception {
-        installPackage(target(TARGET), USER);
-        installPackage(overlay(OVERLAY, TARGET), USER);
-        installPackage(overlay(OVERLAY2, TARGET), USER);
-        installPackage(overlay(OVERLAY3, TARGET2), USER);
+        installAndAssert(target(TARGET), USER,
+                Set.of(new PackageAndUser(TARGET, USER)));
+        installAndAssert(overlay(OVERLAY, TARGET), USER,
+                Set.of(new PackageAndUser(OVERLAY, USER), new PackageAndUser(TARGET, USER)));
+        installAndAssert(overlay(OVERLAY2, TARGET), USER,
+                Set.of(new PackageAndUser(OVERLAY2, USER), new PackageAndUser(TARGET, USER)));
+        installAndAssert(overlay(OVERLAY3, TARGET2), USER,
+                Set.of(new PackageAndUser(OVERLAY3, USER), new PackageAndUser(TARGET2, USER)));
 
         final OverlayManagerServiceImpl impl = getImpl();
         final Map<String, List<OverlayInfo>> everything = impl.getOverlaysForUser(USER);
@@ -129,9 +137,12 @@
 
     @Test
     public void testPriority() throws Exception {
-        installPackage(overlay(OVERLAY, TARGET), USER);
-        installPackage(overlay(OVERLAY2, TARGET), USER);
-        installPackage(overlay(OVERLAY3, TARGET), USER);
+        installAndAssert(overlay(OVERLAY, TARGET), USER,
+                Set.of(new PackageAndUser(OVERLAY, USER), new PackageAndUser(TARGET, USER)));
+        installAndAssert(overlay(OVERLAY2, TARGET), USER,
+                Set.of(new PackageAndUser(OVERLAY2, USER), new PackageAndUser(TARGET, USER)));
+        installAndAssert(overlay(OVERLAY3, TARGET), USER,
+                Set.of(new PackageAndUser(OVERLAY3, USER), new PackageAndUser(TARGET, USER)));
 
         final OverlayManagerServiceImpl impl = getImpl();
         final OverlayInfo o1 = impl.getOverlayInfo(IDENTIFIER, USER);
@@ -158,11 +169,12 @@
         final OverlayManagerServiceImpl impl = getImpl();
         assertNull(impl.getOverlayInfo(IDENTIFIER, USER));
 
-        installPackage(overlay(OVERLAY, TARGET), USER);
+        installAndAssert(overlay(OVERLAY, TARGET), USER,
+                Set.of(new PackageAndUser(OVERLAY, USER), new PackageAndUser(TARGET, USER)));
         assertState(STATE_MISSING_TARGET, IDENTIFIER, USER);
 
-        final FakeDeviceState.PackageBuilder target = target(TARGET);
-        installPackage(target, USER);
+        installAndAssert(target(TARGET), USER,
+                Set.of(new PackageAndUser(TARGET, USER)));
         assertState(STATE_DISABLED, IDENTIFIER, USER);
 
         assertEquals(impl.setEnabled(IDENTIFIER, true, USER),
@@ -170,32 +182,35 @@
         assertState(STATE_ENABLED, IDENTIFIER, USER);
 
         // target upgrades do not change the state of the overlay
-        upgradePackage(target, USER);
+        upgradeAndAssert(target(TARGET), USER,
+                Set.of(new PackageAndUser(TARGET, USER)),
+                Set.of(new PackageAndUser(TARGET, USER)));
         assertState(STATE_ENABLED, IDENTIFIER, USER);
 
-        uninstallPackage(TARGET, USER);
+        uninstallAndAssert(TARGET, USER,
+                Set.of(new PackageAndUser(TARGET, USER)));
         assertState(STATE_MISSING_TARGET, IDENTIFIER, USER);
 
-        installPackage(target, USER);
+        installAndAssert(target(TARGET), USER,
+                Set.of(new PackageAndUser(TARGET, USER)));
         assertState(STATE_ENABLED, IDENTIFIER, USER);
     }
 
     @Test
     public void testOnOverlayPackageUpgraded() throws Exception {
-        final FakeDeviceState.PackageBuilder target = target(TARGET);
-        final FakeDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET);
-        installPackage(target, USER);
-        installPackage(overlay, USER);
-        upgradePackage(overlay, USER);
+        installAndAssert(target(TARGET), USER,
+                Set.of(new PackageAndUser(TARGET, USER)));
+        installAndAssert(overlay(OVERLAY, TARGET), USER,
+                Set.of(new PackageAndUser(OVERLAY, USER), new PackageAndUser(TARGET, USER)));
+        upgradeAndAssert(overlay(OVERLAY, TARGET), USER,
+                Set.of(new PackageAndUser(TARGET, USER)),
+                Set.of(new PackageAndUser(TARGET, USER)));
 
         // upgrade to a version where the overlay has changed its target
-        final FakeDeviceState.PackageBuilder overlay2 = overlay(OVERLAY, "some.other.target");
-        final Pair<Set<PackageAndUser>, Set<PackageAndUser>> pair = upgradePackage(overlay2, USER);
-        assertEquals(pair.first, Set.of(new PackageAndUser(TARGET, USER)));
-        assertEquals(
+        upgradeAndAssert(overlay(OVERLAY, TARGET2), USER,
+                Set.of(new PackageAndUser(TARGET, USER)),
                 Set.of(new PackageAndUser(TARGET, USER),
-                        new PackageAndUser("some.other.target", USER)),
-                pair.second);
+                        new PackageAndUser(TARGET2, USER)));
     }
 
     @Test
@@ -206,13 +221,15 @@
 
         // request succeeded, and there was a change that needs to be
         // propagated to the rest of the system
-        installPackage(target(TARGET), USER);
-        installPackage(overlay(OVERLAY, TARGET), USER);
-        assertEquals(impl.setEnabled(IDENTIFIER, true, USER),
+        installAndAssert(target(TARGET), USER,
                 Set.of(new PackageAndUser(TARGET, USER)));
+        installAndAssert(overlay(OVERLAY, TARGET), USER,
+                Set.of(new PackageAndUser(OVERLAY, USER), new PackageAndUser(TARGET, USER)));
+        assertEquals(Set.of(new PackageAndUser(TARGET, USER)),
+                impl.setEnabled(IDENTIFIER, true, USER));
 
         // request succeeded, but nothing changed
-        assertTrue(impl.setEnabled(IDENTIFIER, true, USER).isEmpty());
+        assertEquals(Set.of(), impl.setEnabled(IDENTIFIER, true, USER));
     }
 
     @Test
@@ -221,16 +238,18 @@
         reinitializeImpl();
 
         addPackage(target(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER);
-        installPackage(target(TARGET), USER);
-        installPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_OK), USER);
+        installAndAssert(target(TARGET), USER,
+                Set.of(new PackageAndUser(TARGET, USER)));
+        installAndAssert(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_OK), USER,
+                Set.of(new PackageAndUser(OVERLAY, USER), new PackageAndUser(TARGET, USER)));
 
         final FakeIdmapDaemon idmapd = getIdmapd();
         final FakeDeviceState state = getState();
-        String overlayPath = state.select(OVERLAY, USER).apkPath;
+        final String overlayPath = state.select(OVERLAY, USER).apkPath;
         assertTrue(idmapd.idmapExists(overlayPath, USER));
 
-        FakeIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
-        assertTrue((CONFIG_SIGNATURE & idmap.policies) == CONFIG_SIGNATURE);
+        final FakeIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
+        assertEquals(CONFIG_SIGNATURE, CONFIG_SIGNATURE & idmap.policies);
     }
 
     @Test
@@ -239,45 +258,51 @@
         reinitializeImpl();
 
         addPackage(target(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER);
-        installPackage(target(TARGET), USER);
-        installPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER);
+        installAndAssert(target(TARGET), USER,
+                Set.of(new PackageAndUser(TARGET, USER)));
+        installAndAssert(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER,
+                Set.of(new PackageAndUser(OVERLAY, USER), new PackageAndUser(TARGET, USER)));
 
         final FakeIdmapDaemon idmapd = getIdmapd();
         final FakeDeviceState state = getState();
-        String overlayPath = state.select(OVERLAY, USER).apkPath;
+        final String overlayPath = state.select(OVERLAY, USER).apkPath;
         assertTrue(idmapd.idmapExists(overlayPath, USER));
 
-        FakeIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
-        assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0);
+        final FakeIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
+        assertEquals(0, CONFIG_SIGNATURE & idmap.policies);
     }
 
     @Test
     public void testConfigSignaturePolicyNoConfig() throws Exception {
         addPackage(target(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER);
-        installPackage(target(TARGET), USER);
-        installPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER);
+        installAndAssert(target(TARGET), USER,
+                Set.of(new PackageAndUser(TARGET, USER)));
+        installAndAssert(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER,
+                Set.of(new PackageAndUser(OVERLAY, USER), new PackageAndUser(TARGET, USER)));
 
         final FakeIdmapDaemon idmapd = getIdmapd();
         final FakeDeviceState state = getState();
-        String overlayPath = state.select(OVERLAY, USER).apkPath;
+        final String overlayPath = state.select(OVERLAY, USER).apkPath;
         assertTrue(idmapd.idmapExists(overlayPath, USER));
 
-        FakeIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
-        assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0);
+        final FakeIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
+        assertEquals(0, CONFIG_SIGNATURE & idmap.policies);
     }
 
     @Test
     public void testConfigSignaturePolicyNoRefPkg() throws Exception {
-        installPackage(target(TARGET), USER);
-        installPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER);
+        installAndAssert(target(TARGET), USER,
+                Set.of(new PackageAndUser(TARGET, USER)));
+        installAndAssert(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER,
+                Set.of(new PackageAndUser(OVERLAY, USER), new PackageAndUser(TARGET, USER)));
 
         final FakeIdmapDaemon idmapd = getIdmapd();
         final FakeDeviceState state = getState();
-        String overlayPath = state.select(OVERLAY, USER).apkPath;
+        final String overlayPath = state.select(OVERLAY, USER).apkPath;
         assertTrue(idmapd.idmapExists(overlayPath, USER));
 
-        FakeIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
-        assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0);
+        final FakeIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
+        assertEquals(0, CONFIG_SIGNATURE & idmap.policies);
     }
 
     @Test
@@ -286,8 +311,10 @@
         reinitializeImpl();
 
         addPackage(app(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER);
-        installPackage(target(TARGET), USER);
-        installPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER);
+        installAndAssert(target(TARGET), USER,
+                Set.of(new PackageAndUser(TARGET, USER)));
+        installAndAssert(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER,
+                Set.of(new PackageAndUser(OVERLAY, USER), new PackageAndUser(TARGET, USER)));
 
         final FakeIdmapDaemon idmapd = getIdmapd();
         final FakeDeviceState state = getState();
@@ -295,6 +322,6 @@
         assertTrue(idmapd.idmapExists(overlayPath, USER));
 
         FakeIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
-        assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0);
+        assertEquals(0, CONFIG_SIGNATURE & idmap.policies);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
index 16e0329..29ff9f4 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
@@ -139,8 +139,19 @@
         mState.add(pkg, userId);
     }
 
-    void configureSystemOverlay(String packageName, boolean mutable, boolean enabled,
+    enum ConfigState {
+        IMMUTABLE_DISABLED,
+        IMMUTABLE_ENABLED,
+        MUTABLE_DISABLED,
+        MUTABLE_ENABLED
+    }
+
+    void configureSystemOverlay(@NonNull String packageName, @NonNull ConfigState state,
             int priority) {
+        final boolean mutable = state == ConfigState.MUTABLE_DISABLED
+                || state == ConfigState.MUTABLE_ENABLED;
+        final boolean enabled = state == ConfigState.IMMUTABLE_ENABLED
+                || state == ConfigState.MUTABLE_ENABLED;
         when(mOverlayConfig.getPriority(packageName)).thenReturn(priority);
         when(mOverlayConfig.isEnabled(packageName)).thenReturn(enabled);
         when(mOverlayConfig.isMutable(packageName)).thenReturn(mutable);
@@ -154,13 +165,14 @@
      *
      * @throws IllegalStateException if the package is currently installed
      */
-    Set<PackageAndUser> installPackage(FakeDeviceState.PackageBuilder pkg, int userId)
+    void installAndAssert(@NonNull FakeDeviceState.PackageBuilder pkg, int userId,
+            @NonNull Set<PackageAndUser> onAddedUpdatedPackages)
             throws OperationFailedException {
         if (mState.select(pkg.packageName, userId) != null) {
             throw new IllegalStateException("package " + pkg.packageName + " already installed");
         }
         mState.add(pkg, userId);
-        return CollectionUtils.emptyIfNull(mImpl.onPackageAdded(pkg.packageName, userId));
+        assertEquals(onAddedUpdatedPackages, mImpl.onPackageAdded(pkg.packageName, userId));
     }
 
     /**
@@ -172,25 +184,20 @@
      * {@link android.content.Intent#ACTION_PACKAGE_ADDED} broadcast with the
      * {@link android.content.Intent#EXTRA_REPLACING} extra.
      *
-     * @return the two Optional<PackageAndUser> objects from starting and finishing the upgrade
-     *
      * @throws IllegalStateException if the package is not currently installed
      */
-    Pair<Set<PackageAndUser>, Set<PackageAndUser>> upgradePackage(
-            FakeDeviceState.PackageBuilder pkg, int userId) throws OperationFailedException {
+    void upgradeAndAssert(FakeDeviceState.PackageBuilder pkg, int userId,
+            @NonNull Set<PackageAndUser> onReplacingUpdatedPackages,
+            @NonNull Set<PackageAndUser> onReplacedUpdatedPackages)
+            throws OperationFailedException {
         final FakeDeviceState.Package replacedPackage = mState.select(pkg.packageName, userId);
         if (replacedPackage == null) {
             throw new IllegalStateException("package " + pkg.packageName + " not installed");
         }
 
-        final Set<PackageAndUser> updatedPackages1 =
-                CollectionUtils.emptyIfNull(mImpl.onPackageReplacing(pkg.packageName, userId));
-
+        assertEquals(onReplacingUpdatedPackages, mImpl.onPackageReplacing(pkg.packageName, userId));
         mState.add(pkg, userId);
-        final Set<PackageAndUser> updatedPackages2 =
-                CollectionUtils.emptyIfNull(mImpl.onPackageReplaced(pkg.packageName, userId));
-
-        return Pair.create(updatedPackages1, updatedPackages2);
+        assertEquals(onReplacedUpdatedPackages, mImpl.onPackageReplaced(pkg.packageName, userId));
     }
 
     /**
@@ -201,13 +208,14 @@
      *
      * @throws IllegalStateException if the package is not currently installed
      */
-    Set<PackageAndUser> uninstallPackage(String packageName, int userId) {
+    void uninstallAndAssert(@NonNull String packageName, int userId,
+            @NonNull Set<PackageAndUser> onRemovedUpdatedPackages) {
         final FakeDeviceState.Package pkg = mState.select(packageName, userId);
         if (pkg == null) {
-            throw new IllegalStateException("package " + packageName+ " not installed");
+            throw new IllegalStateException("package " + packageName + " not installed");
         }
         mState.remove(pkg.packageName);
-        return CollectionUtils.emptyIfNull(mImpl.onPackageRemoved(packageName, userId));
+        assertEquals(onRemovedUpdatedPackages, mImpl.onPackageRemoved(pkg.packageName, userId));
     }
 
     /** Represents the state of packages installed on a fake device. */
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 59458e8..d63a467 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -59,10 +59,10 @@
 
 import com.android.permission.persistence.RuntimePermissionsPersistence;
 import com.android.server.LocalServices;
-import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
 import com.android.server.pm.permission.LegacyPermissionDataProvider;
+import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
 import com.android.server.utils.WatchableTester;
 
 import com.google.common.truth.Truth;
@@ -1197,7 +1197,7 @@
     private Settings makeSettings() {
         return new Settings(InstrumentationRegistry.getContext().getFilesDir(),
                 mRuntimePermissionsPersistence, mPermissionDataProvider,
-                mDomainVerificationManager, new Object());
+                mDomainVerificationManager, new PackageManagerTracedLock());
     }
 
     private void verifyKeySetMetaData(Settings settings)
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index ba60111..128cbaa 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -48,6 +48,7 @@
 import android.content.pm.parsing.component.ParsedPermissionGroup;
 import android.content.pm.parsing.component.ParsedProvider;
 import android.content.pm.parsing.component.ParsedService;
+import android.content.pm.parsing.component.ParsedUsesPermission;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.platform.test.annotations.Presubmit;
@@ -854,7 +855,7 @@
                 .addProvider(new ParsedProvider())
                 .addService(new ParsedService())
                 .addInstrumentation(new ParsedInstrumentation())
-                .addRequestedPermission("foo7")
+                .addUsesPermission(new ParsedUsesPermission("foo7", 0))
                 .addImplicitPermission("foo25")
                 .addProtectedBroadcast("foo8")
                 .setStaticSharedLibName("foo23")
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
index b5add84..8e1fc16 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -43,6 +43,7 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.SharedLibraryInfo;
 import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.component.ParsedUsesPermission;
 import android.content.res.TypedArray;
 import android.os.Environment;
 import android.os.UserHandle;
@@ -429,7 +430,7 @@
     @Test
     public void factoryTestFlagSet() throws Exception {
         final ParsingPackage basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
-                .addRequestedPermission(Manifest.permission.FACTORY_TEST);
+                .addUsesPermission(new ParsedUsesPermission(Manifest.permission.FACTORY_TEST, 0));
 
         final PackageManagerService.ScanResult scanResult = PackageManagerService.scanPackageOnlyLI(
                 createBasicScanRequestBuilder(basicPackage).build(),
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java
index e605d75..13d75a7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java
@@ -245,14 +245,6 @@
                 UID,
                 COMPILATION_REASON,
                 COMPILER_FILTER,
-                ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_DEX_CODE_BYTES,
-                DEX_CONTENT.length,
-                dexMetadataType);
-        inorder.verify(mockLogger).write(
-                SESSION_ID,
-                UID,
-                COMPILATION_REASON,
-                COMPILER_FILTER,
                 ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_TOTAL_TIME,
                 COMPILE_TIME,
                 dexMetadataType);
diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
index 9b8a2a8..324e592 100644
--- a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
@@ -18,6 +18,7 @@
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertThat;
+import static org.mockito.AdditionalMatchers.not;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -70,6 +71,7 @@
     private FileWriter mUncryptUpdateFileWriter;
     private LockSettingsInternal mLockSettingsInternal;
     private IBootControl mIBootControl;
+    private RecoverySystemServiceTestable.IMetricsReporter mMetricsReporter;
 
     private static final String FAKE_OTA_PACKAGE_NAME = "fake.ota.package";
     private static final String FAKE_OTHER_PACKAGE_NAME = "fake.other.package";
@@ -94,9 +96,11 @@
         when(mIBootControl.getCurrentSlot()).thenReturn(0);
         when(mIBootControl.getActiveBootSlot()).thenReturn(1);
 
+        mMetricsReporter = mock(RecoverySystemServiceTestable.IMetricsReporter.class);
+
         mRecoverySystemService = new RecoverySystemServiceTestable(mContext, mSystemProperties,
                 powerManager, mUncryptUpdateFileWriter, mUncryptSocket, mLockSettingsInternal,
-                mIBootControl);
+                mIBootControl, mMetricsReporter);
     }
 
     @Test
@@ -227,12 +231,24 @@
     }
 
     @Test
+    public void requestLskf_reportMetrics() throws Exception {
+        IntentSender intentSender = mock(IntentSender.class);
+        assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, intentSender),
+                is(true));
+        verify(mMetricsReporter).reportRebootEscrowPreparationMetrics(
+                eq(1000), eq(0) /* need preparation */, eq(1) /* client count */);
+    }
+
+
+    @Test
     public void requestLskf_success() throws Exception {
         IntentSender intentSender = mock(IntentSender.class);
         assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, intentSender),
                 is(true));
         mRecoverySystemService.onPreparedForReboot(true);
         verify(intentSender).sendIntent(any(), anyInt(), any(), any(), any());
+        verify(mMetricsReporter).reportRebootEscrowLskfCapturedMetrics(
+                eq(1000), eq(1) /* client count */, anyInt() /* duration */);
     }
 
     @Test
@@ -255,6 +271,8 @@
         assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, intentSender),
                 is(true));
         verify(intentSender, never()).sendIntent(any(), anyInt(), any(), any(), any());
+        verify(mMetricsReporter, never()).reportRebootEscrowLskfCapturedMetrics(
+                anyInt(), anyInt(), anyInt());
     }
 
     @Test
@@ -337,6 +355,9 @@
         assertThat(mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, "ab-update", true),
                 is(true));
         verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean());
+        verify(mMetricsReporter).reportRebootEscrowRebootMetrics(eq(0), eq(1000),
+                eq(1) /* client count */, eq(1) /* request count */, eq(true) /* slot switch */,
+                anyBoolean(), anyInt(), eq(1) /* lskf capture count */);
     }
 
 
@@ -373,6 +394,20 @@
         verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean());
     }
 
+    @Test
+    public void rebootWithLskf_multiClient_success_reportMetrics() throws Exception {
+        assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, null), is(true));
+        assertThat(mRecoverySystemService.requestLskf(FAKE_OTHER_PACKAGE_NAME, null), is(true));
+        mRecoverySystemService.onPreparedForReboot(true);
+
+        // Client B's clear won't affect client A's preparation.
+        assertThat(mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, "ab-update", true),
+                is(true));
+        verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean());
+        verify(mMetricsReporter).reportRebootEscrowRebootMetrics(eq(0), eq(1000),
+                eq(2) /* client count */, eq(1) /* request count */, eq(true) /* slot switch */,
+                anyBoolean(), anyInt(), eq(1) /* lskf capture count */);
+    }
 
     @Test
     public void rebootWithLskf_multiClient_ClientBSuccess() throws Exception {
@@ -384,12 +419,18 @@
         assertThat(mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, null, true),
                 is(false));
         verifyNoMoreInteractions(mIPowerManager);
+        verify(mMetricsReporter).reportRebootEscrowRebootMetrics(not(eq(0)), eq(1000),
+                eq(1) /* client count */, eq(1) /* request count */, eq(true) /* slot switch */,
+                anyBoolean(), anyInt(), eq(1) /* lskf capture count */);
 
         assertThat(mRecoverySystemService.requestLskf(FAKE_OTHER_PACKAGE_NAME, null), is(true));
         assertThat(
                 mRecoverySystemService.rebootWithLskf(FAKE_OTHER_PACKAGE_NAME, "ab-update", true),
                 is(true));
         verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean());
+        verify(mMetricsReporter).reportRebootEscrowRebootMetrics(eq(0), eq(2000),
+                eq(1) /* client count */, eq(1) /* request count */, eq(true) /* slot switch */,
+                anyBoolean(), anyInt(), eq(1) /* lskf capture count */);
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java
index 0727e5a..a894178 100644
--- a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java
@@ -32,11 +32,12 @@
         private final UncryptSocket mUncryptSocket;
         private final LockSettingsInternal mLockSettingsInternal;
         private final IBootControl mIBootControl;
+        private final IMetricsReporter mIMetricsReporter;
 
         MockInjector(Context context, FakeSystemProperties systemProperties,
                 PowerManager powerManager, FileWriter uncryptPackageFileWriter,
                 UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal,
-                IBootControl bootControl) {
+                IBootControl bootControl, IMetricsReporter metricsReporter) {
             super(context);
             mSystemProperties = systemProperties;
             mPowerManager = powerManager;
@@ -44,6 +45,7 @@
             mUncryptSocket = uncryptSocket;
             mLockSettingsInternal = lockSettingsInternal;
             mIBootControl = bootControl;
+            mIMetricsReporter = metricsReporter;
         }
 
         @Override
@@ -94,14 +96,45 @@
         public IBootControl getBootControl() {
             return mIBootControl;
         }
+        @Override
+        public int getUidFromPackageName(String packageName) {
+            if ("fake.ota.package".equals(packageName)) {
+                return 1000;
+            }
+            if ("fake.other.package".equals(packageName)) {
+                return 2000;
+            }
+            return 3000;
+        }
+
+        @Override
+        public void reportRebootEscrowPreparationMetrics(int uid, int requestResult,
+                int requestedClientCount) {
+            mIMetricsReporter.reportRebootEscrowPreparationMetrics(uid, requestResult,
+                    requestedClientCount);
+        }
+
+        public void reportRebootEscrowLskfCapturedMetrics(int uid, int requestedClientCount,
+                int requestedToLskfCapturedDurationInSeconds) {
+            mIMetricsReporter.reportRebootEscrowLskfCapturedMetrics(uid, requestedClientCount,
+                    requestedToLskfCapturedDurationInSeconds);
+        }
+
+        public void reportRebootEscrowRebootMetrics(int errorCode, int uid, int preparedClientCount,
+                int requestCount, boolean slotSwitch, boolean serverBased,
+                int lskfCapturedToRebootDurationInSeconds, int lskfCapturedCounts) {
+            mIMetricsReporter.reportRebootEscrowRebootMetrics(errorCode, uid, preparedClientCount,
+                    requestCount, slotSwitch, serverBased, lskfCapturedToRebootDurationInSeconds,
+                    lskfCapturedCounts);
+        }
     }
 
     RecoverySystemServiceTestable(Context context, FakeSystemProperties systemProperties,
             PowerManager powerManager, FileWriter uncryptPackageFileWriter,
             UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal,
-            IBootControl bootControl) {
+            IBootControl bootControl, IMetricsReporter metricsReporter) {
         super(new MockInjector(context, systemProperties, powerManager, uncryptPackageFileWriter,
-                uncryptSocket, lockSettingsInternal, bootControl));
+                uncryptSocket, lockSettingsInternal, bootControl, metricsReporter));
     }
 
     public static class FakeSystemProperties {
@@ -131,4 +164,17 @@
             return mCtlStart;
         }
     }
+
+    public interface IMetricsReporter {
+        void reportRebootEscrowPreparationMetrics(int uid, int requestResult,
+                int requestedClientCount);
+
+        void reportRebootEscrowLskfCapturedMetrics(int uid, int requestedClientCount,
+                int requestedToLskfCapturedDurationInSeconds);
+
+        void reportRebootEscrowRebootMetrics(int errorCode, int uid, int preparedClientCount,
+                int requestCount, boolean slotSwitch, boolean serverBased,
+                int lskfCapturedToRebootDurationInSeconds, int lskfCapturedCounts);
+    }
+
 }
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/ConfigurationInternalTest.java b/services/tests/servicestests/src/com/android/server/timedetector/ConfigurationInternalTest.java
new file mode 100644
index 0000000..d4222e6
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timedetector/ConfigurationInternalTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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.timedetector;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.time.Capabilities;
+import android.app.time.TimeCapabilities;
+import android.app.time.TimeCapabilitiesAndConfig;
+import android.app.time.TimeConfiguration;
+import android.os.UserHandle;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class ConfigurationInternalTest {
+
+    @Test
+    public void capabilitiesAndConfig() {
+        int userId = 112233;
+        ConfigurationInternal configurationInternal = new ConfigurationInternal.Builder(userId)
+                .setAutoDetectionEnabled(true)
+                .setUserConfigAllowed(true)
+                .build();
+
+        TimeCapabilities timeCapabilities = new TimeCapabilities.Builder(UserHandle.of(userId))
+                .setConfigureAutoTimeDetectionEnabledCapability(Capabilities.CAPABILITY_POSSESSED)
+                .setSuggestTimeManuallyCapability(Capabilities.CAPABILITY_POSSESSED)
+                .build();
+        TimeConfiguration timeConfiguration = new TimeConfiguration.Builder()
+                .setAutoDetectionEnabled(true)
+                .build();
+        TimeCapabilitiesAndConfig expected =
+                new TimeCapabilitiesAndConfig(timeCapabilities, timeConfiguration);
+
+        assertThat(configurationInternal.capabilitiesAndConfig()).isEqualTo(expected);
+    }
+
+}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
index bbf11fd..1068270 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -328,6 +328,11 @@
         }
 
         @Override
+        public ConfigurationInternal getConfigurationInternal(int userId) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
         public void handleAutoTimeConfigChanged() {
             mHandleAutoTimeDetectionChangedCalled = true;
         }
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
index f7a498b..095703e 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
@@ -1158,6 +1158,11 @@
         }
 
         @Override
+        public ConfigurationInternal configurationInternal(int userId) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
         public void acquireWakeLock() {
             if (mWakeLockAcquired) {
                 fail("Wake lock already acquired");
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 0036982..aa46e7e 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
@@ -16,10 +16,10 @@
 
 package com.android.server.timezonedetector;
 
-import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED;
-import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
-import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED;
-import static android.app.time.TimeZoneCapabilities.CAPABILITY_POSSESSED;
+import static android.app.time.Capabilities.CAPABILITY_NOT_ALLOWED;
+import static android.app.time.Capabilities.CAPABILITY_NOT_APPLICABLE;
+import static android.app.time.Capabilities.CAPABILITY_NOT_SUPPORTED;
+import static android.app.time.Capabilities.CAPABILITY_POSSESSED;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
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 624c3de..86b1620 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -1390,6 +1390,21 @@
     }
 
     @Test
+    public void testRestrictApp_MainReason() throws Exception {
+        mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
+                REASON_MAIN_DEFAULT);
+        mInjector.mElapsedRealtime += 4 * RESTRICTED_THRESHOLD;
+
+        mController.restrictApp(PACKAGE_1, USER_ID, REASON_MAIN_PREDICTED, 0);
+        // Call should be ignored.
+        assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
+
+        mController.restrictApp(PACKAGE_1, USER_ID, REASON_MAIN_FORCED_BY_USER, 0);
+        // Call should go through
+        assertEquals(STANDBY_BUCKET_RESTRICTED, getStandbyBucket(mController, PACKAGE_1));
+    }
+
+    @Test
     public void testAddActiveDeviceAdmin() throws Exception {
         assertActiveAdmins(USER_ID, (String[]) null);
         assertActiveAdmins(USER_ID2, (String[]) null);
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 1905e2f..ec3a1af 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -4038,6 +4038,24 @@
     }
 
     @Test
+    public void testVisitUris_audioContentsString() throws Exception {
+        final Uri audioContents = Uri.parse("content://com.example/audio");
+
+        Bundle extras = new Bundle();
+        extras.putString(Notification.EXTRA_AUDIO_CONTENTS_URI, audioContents.toString());
+
+        Notification n = new Notification.Builder(mContext, "a")
+                .setContentTitle("notification with uris")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon)
+                .addExtras(extras)
+                .build();
+
+        Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
+        n.visitUris(visitor);
+        verify(visitor, times(1)).accept(eq(audioContents));
+    }
+
+    @Test
     public void testSetNotificationPolicy_preP_setOldFields() {
         ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
         mService.mZenModeHelper = mZenModeHelper;
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 c19f348..96ebd24 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -1687,6 +1687,7 @@
     public void testIsSnapshotCompatible() {
         final ActivityRecord activity = createActivityWithTask();
         final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder()
+                .setTopActivityComponent(activity.mActivityComponent)
                 .setRotation(activity.getWindowConfiguration().getRotation())
                 .build();
 
@@ -1697,6 +1698,26 @@
         assertFalse(activity.isSnapshotCompatible(snapshot));
     }
 
+    /**
+     * Test that the snapshot should be obsoleted if the top activity changed.
+     */
+    @Test
+    public void testIsSnapshotCompatibleTopActivityChanged() {
+        final ActivityRecord activity = createActivityWithTask();
+        final ActivityRecord secondActivity = new ActivityBuilder(mAtm)
+                .setTask(activity.getTask())
+                .setOnTop(true)
+                .build();
+        final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder()
+                .setTopActivityComponent(secondActivity.mActivityComponent)
+                .build();
+
+        assertTrue(secondActivity.isSnapshotCompatible(snapshot));
+
+        // Emulate the top activity changed.
+        assertFalse(activity.isSnapshotCompatible(snapshot));
+    }
+
     @Test
     public void testFixedRotationSnapshotStartingWindow() {
         final ActivityRecord activity = createActivityWithTask();
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 67fe7bf..33bcc5b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -119,6 +119,7 @@
 import android.view.SurfaceControl.Transaction;
 import android.view.View;
 import android.view.WindowManager;
+import android.window.WindowContainerToken;
 
 import androidx.test.filters.SmallTest;
 
@@ -1611,6 +1612,54 @@
     }
 
     @Test
+    public void testShellTransitRotation() {
+        DisplayContent dc = createNewDisplay();
+
+        // Set-up mock shell transitions
+        final TestTransitionPlayer testPlayer = new TestTransitionPlayer(
+                mAtm.getTransitionController(), mAtm.mWindowOrganizerController);
+        mAtm.getTransitionController().registerTransitionPlayer(testPlayer);
+
+        final DisplayRotation dr = dc.getDisplayRotation();
+        doCallRealMethod().when(dr).updateRotationUnchecked(anyBoolean());
+        // Rotate 180 degree so the display doesn't have configuration change. This condition is
+        // used for the later verification of stop-freezing (without setting mWaitingForConfig).
+        doReturn((dr.getRotation() + 2) % 4).when(dr).rotationForOrientation(anyInt(), anyInt());
+        mWm.mDisplayRotationController =
+                new IDisplayWindowRotationController.Stub() {
+                    @Override
+                    public void onRotateDisplay(int displayId, int fromRotation, int toRotation,
+                            IDisplayWindowRotationCallback callback) {
+                        try {
+                            callback.continueRotateDisplay(toRotation, null);
+                        } catch (RemoteException e) {
+                            assertTrue(false);
+                        }
+                    }
+                };
+
+        // kill any existing rotation animation (vestigial from test setup).
+        dc.setRotationAnimation(null);
+
+        final int origRot = dc.getConfiguration().windowConfiguration.getRotation();
+
+        mWm.updateRotation(true /* alwaysSendConfiguration */, false /* forceRelayout */);
+        // Should create a transition request without performing rotation
+        assertNotNull(testPlayer.mLastRequest);
+        assertEquals(origRot, dc.getConfiguration().windowConfiguration.getRotation());
+
+        // Once transition starts, rotation is applied and transition shows DC rotating.
+        testPlayer.start();
+        assertNotEquals(origRot, dc.getConfiguration().windowConfiguration.getRotation());
+        assertNotNull(testPlayer.mLastReady);
+        assertEquals(dc, DisplayRotation.getDisplayFromTransition(testPlayer.mLastTransit));
+        WindowContainerToken dcToken = dc.mRemoteToken.toWindowContainerToken();
+        assertNotEquals(testPlayer.mLastReady.getChange(dcToken).getEndRotation(),
+                testPlayer.mLastReady.getChange(dcToken).getStartRotation());
+        testPlayer.finish();
+    }
+
+    @Test
     public void testGetOrCreateRootHomeTask_defaultDisplay() {
         TaskDisplayArea defaultTaskDisplayArea = mWm.mRoot.getDefaultTaskDisplayArea();
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index 7f9e7da..4e2697a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -134,6 +134,7 @@
                 null, TYPE_BASE_APPLICATION, activity, name, ownerId, false, new TestIWindow());
         window.mInputChannel = new InputChannel();
         window.mHasSurface = true;
+        mWm.mInputToWindowMap.put(window.mInputChannelToken, window);
         return window;
     }
 
@@ -226,7 +227,7 @@
                     // Verify after consuming that the drag surface is relinquished
                     try {
                         mTarget.mDeferDragStateClosed = true;
-
+                        mTarget.reportDropWindow(mWindow.mInputChannelToken, 0, 0);
                         // Verify the drop event includes the drag surface
                         mTarget.handleMotionEvent(false, 0, 0);
                         final DragEvent dropEvent = dragEvents.get(dragEvents.size() - 1);
@@ -355,6 +356,7 @@
 
     private void doDragAndDrop(int flags, ClipData data, float dropX, float dropY) {
         startDrag(flags, data, () -> {
+            mTarget.reportDropWindow(mWindow.mInputChannelToken, dropX, dropY);
             mTarget.handleMotionEvent(false, dropX, dropY);
             mToken = mWindow.mClient.asBinder();
         });
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index c98e013..956c277 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -18,11 +18,13 @@
 
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
 import static android.view.WindowManager.TRANSIT_OLD_NONE;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -34,8 +36,11 @@
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
 
+import static junit.framework.Assert.fail;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
@@ -96,7 +101,7 @@
         mAdapter = new RemoteAnimationAdapter(mMockRunner, 100, 50, true /* changeNeedsSnapshot */);
         mAdapter.setCallingPidUid(123, 456);
         runWithScissors(mWm.mH, () -> mHandler = new TestHandler(null, mClock), 0);
-        mController = new RemoteAnimationController(mWm, mAdapter, mHandler);
+        mController = new RemoteAnimationController(mWm, mDisplayContent, mAdapter, mHandler);
     }
 
     private WindowState createAppOverlayWindow() {
@@ -525,6 +530,110 @@
         }
     }
 
+    @Test
+    public void testNonAppTarget_sendNavBar() throws Exception {
+        final int transit = TRANSIT_OLD_TASK_OPEN;
+        final AnimationAdapter adapter = setupForNonAppTargetNavBar(transit, true);
+
+        final ArgumentCaptor<RemoteAnimationTarget[]> nonAppsCaptor =
+                ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+        final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
+                ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
+        verify(mMockRunner).onAnimationStart(eq(transit), any(), any(),
+                nonAppsCaptor.capture(), finishedCaptor.capture());
+        boolean containNavTarget = false;
+        for (int i = 0; i < nonAppsCaptor.getValue().length; i++) {
+            if (nonAppsCaptor.getValue()[0].windowType == TYPE_NAVIGATION_BAR) {
+                containNavTarget = true;
+                break;
+            }
+        }
+        assertTrue(containNavTarget);
+        assertEquals(1, mController.mPendingNonAppAnimations.size());
+        final NonAppWindowAnimationAdapter nonAppAdapter =
+                mController.mPendingNonAppAnimations.get(0);
+        spyOn(nonAppAdapter.getLeashFinishedCallback());
+
+        finishedCaptor.getValue().onAnimationFinished();
+        verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION),
+                eq(adapter));
+        verify(nonAppAdapter.getLeashFinishedCallback())
+                .onAnimationFinished(nonAppAdapter.getLastAnimationType(), nonAppAdapter);
+    }
+
+    @Test
+    public void testNonAppTarget_notSendNavBar_notAttachToApp() throws Exception {
+        final int transit = TRANSIT_OLD_TASK_OPEN;
+        setupForNonAppTargetNavBar(transit, false);
+
+        final ArgumentCaptor<RemoteAnimationTarget[]> nonAppsCaptor =
+                ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+        verify(mMockRunner).onAnimationStart(eq(transit),
+                any(), any(), nonAppsCaptor.capture(), any());
+        for (int i = 0; i < nonAppsCaptor.getValue().length; i++) {
+            if (nonAppsCaptor.getValue()[0].windowType == TYPE_NAVIGATION_BAR) {
+                fail("Non-app animation target must not contain navbar");
+            }
+        }
+    }
+
+    @Test
+    public void testNonAppTarget_notSendNavBar_controlledByFixedRotation() throws Exception {
+        final FixedRotationAnimationController mockController =
+                mock(FixedRotationAnimationController.class);
+        doReturn(mockController).when(mDisplayContent).getFixedRotationAnimationController();
+        final int transit = TRANSIT_OLD_TASK_OPEN;
+        setupForNonAppTargetNavBar(transit, true);
+
+        final ArgumentCaptor<RemoteAnimationTarget[]> nonAppsCaptor =
+                ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+        verify(mMockRunner).onAnimationStart(eq(transit),
+                any(), any(), nonAppsCaptor.capture(), any());
+        for (int i = 0; i < nonAppsCaptor.getValue().length; i++) {
+            if (nonAppsCaptor.getValue()[0].windowType == TYPE_NAVIGATION_BAR) {
+                fail("Non-app animation target must not contain navbar");
+            }
+        }
+    }
+
+    @Test
+    public void testNonAppTarget_notSendNavBar_controlledByRecents() throws Exception {
+        final RecentsAnimationController mockController =
+                mock(RecentsAnimationController.class);
+        doReturn(mockController).when(mWm).getRecentsAnimationController();
+        final int transit = TRANSIT_OLD_TASK_OPEN;
+        setupForNonAppTargetNavBar(transit, true);
+
+        final ArgumentCaptor<RemoteAnimationTarget[]> nonAppsCaptor =
+                ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+        verify(mMockRunner).onAnimationStart(eq(transit),
+                any(), any(), nonAppsCaptor.capture(), any());
+        for (int i = 0; i < nonAppsCaptor.getValue().length; i++) {
+            if (nonAppsCaptor.getValue()[0].windowType == TYPE_NAVIGATION_BAR) {
+                fail("Non-app animation target must not contain navbar");
+            }
+        }
+    }
+
+    private AnimationAdapter setupForNonAppTargetNavBar(int transit, boolean shouldAttachNavBar) {
+        final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
+        mDisplayContent.mOpeningApps.add(win.mActivityRecord);
+        final WindowState navBar = createWindow(null, TYPE_NAVIGATION_BAR, "NavigationBar");
+        mDisplayContent.getDisplayPolicy().addWindowLw(navBar, navBar.mAttrs);
+        final DisplayPolicy policy = mDisplayContent.getDisplayPolicy();
+        spyOn(policy);
+        doReturn(shouldAttachNavBar).when(policy).shouldAttachNavBarToAppDuringTransition();
+
+        final AnimationAdapter adapter = mController.createRemoteAnimationRecord(
+                win.mActivityRecord, new Point(50, 100), null,
+                new Rect(50, 100, 150, 150), null).mAdapter;
+        adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
+                mFinishedCallback);
+        mController.goodToGo(transit);
+        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+        return adapter;
+    }
+
     private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) {
         verify(binder, atLeast(0)).asBinder();
         verifyNoMoreInteractions(binder);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 171aa76..1b114c1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -116,8 +116,7 @@
         final Task rootTask = new TaskBuilder(mSupervisor).build();
         final Task task1 = new TaskBuilder(mSupervisor).setParentTask(rootTask).build();
         new ActivityBuilder(mAtm).setTask(task1).build().mVisibleRequested = true;
-        // RootWindowContainer#invalidateTaskLayers should post to update.
-        waitHandlerIdle(mWm.mH);
+        mWm.mRoot.rankTaskLayers();
 
         assertEquals(1, task1.mLayerRank);
         // Only tasks that directly contain activities have a ranking.
@@ -125,7 +124,7 @@
 
         final Task task2 = new TaskBuilder(mSupervisor).build();
         new ActivityBuilder(mAtm).setTask(task2).build().mVisibleRequested = true;
-        waitHandlerIdle(mWm.mH);
+        mWm.mRoot.rankTaskLayers();
 
         // Note that ensureActivitiesVisible is disabled in SystemServicesTestRule, so both the
         // activities have the visible rank.
@@ -134,6 +133,7 @@
         assertEquals(1, task2.mLayerRank);
 
         task2.moveToBack("test", null /* task */);
+        // RootWindowContainer#invalidateTaskLayers should post to update.
         waitHandlerIdle(mWm.mH);
 
         assertEquals(1, task1.mLayerRank);
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 5c7e580..70c2971 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -27,6 +27,8 @@
 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.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
@@ -325,6 +327,22 @@
     }
 
     @Test
+    public void testIsLetterboxed_activityShowsWallpaper_returnsFalse() {
+        setUpDisplaySizeWithApp(1000, 2500);
+        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+        prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE);
+        final WindowState window = createWindow(null, TYPE_BASE_APPLICATION, mActivity, "window");
+
+        assertEquals(window, mActivity.findMainWindow());
+        assertTrue(mActivity.isLetterboxed(mActivity.findMainWindow()));
+
+        window.mAttrs.flags |= FLAG_SHOW_WALLPAPER;
+
+        assertFalse(mActivity.isLetterboxed(mActivity.findMainWindow()));
+    }
+
+    @Test
     public void testAspectRatioMatchParentBoundsAndImeAttachable() {
         setUpApp(new TestDisplayContent.Builder(mAtm, 1000, 2000)
                 .setSystemDecorations(true).build());
diff --git a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
index 6c72249..bb9e24f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
+++ b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
@@ -198,11 +198,6 @@
     }
 
     @Override
-    public SurfaceControl.Transaction setEarlyWakeup() {
-        return this;
-    }
-
-    @Override
     public SurfaceControl.Transaction setMetadata(SurfaceControl sc, int key, int data) {
         return this;
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
index edf7056..b5219fd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
@@ -28,7 +28,6 @@
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
-import android.window.TaskSnapshot;
 import android.content.ComponentName;
 import android.content.ContextWrapper;
 import android.content.res.Resources;
@@ -42,6 +41,7 @@
 import android.hardware.HardwareBuffer;
 import android.os.UserManager;
 import android.view.Surface;
+import android.window.TaskSnapshot;
 
 import com.android.server.LocalServices;
 import com.android.server.pm.UserManagerInternal;
@@ -154,10 +154,16 @@
         private int mWindowingMode = WINDOWING_MODE_FULLSCREEN;
         private int mSystemUiVisibility = 0;
         private int mRotation = Surface.ROTATION_0;
+        private ComponentName mTopActivityComponent = new ComponentName("", "");
 
         TaskSnapshotBuilder() {
         }
 
+        TaskSnapshotBuilder setTopActivityComponent(ComponentName topActivityComponent) {
+            mTopActivityComponent = topActivityComponent;
+            return this;
+        }
+
         TaskSnapshotBuilder setScaleFraction(float scale) {
             mScaleFraction = scale;
             return this;
@@ -199,7 +205,7 @@
             Canvas c = buffer.lockCanvas();
             c.drawColor(Color.RED);
             buffer.unlockCanvasAndPost(c);
-            return new TaskSnapshot(MOCK_SNAPSHOT_ID, new ComponentName("", ""),
+            return new TaskSnapshot(MOCK_SNAPSHOT_ID, mTopActivityComponent,
                     HardwareBuffer.createFromGraphicBuffer(buffer),
                     ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT,
                     mRotation, taskSize, TEST_INSETS,
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 779457b..b210dfb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -60,6 +60,7 @@
 import static org.mockito.Mockito.mock;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.IApplicationThread;
@@ -90,7 +91,10 @@
 import android.view.WindowManager;
 import android.view.WindowManager.DisplayImePolicy;
 import android.window.ITaskOrganizer;
+import android.window.ITransitionPlayer;
 import android.window.StartingWindowInfo;
+import android.window.TransitionInfo;
+import android.window.TransitionRequestInfo;
 
 import com.android.internal.policy.AttributeCache;
 import com.android.internal.util.ArrayUtils;
@@ -1359,4 +1363,48 @@
             mHasSurface = hadSurface;
         }
     }
+
+    class TestTransitionPlayer extends ITransitionPlayer.Stub {
+        final TransitionController mController;
+        final WindowOrganizerController mOrganizer;
+        Transition mLastTransit = null;
+        TransitionRequestInfo mLastRequest = null;
+        TransitionInfo mLastReady = null;
+
+        TestTransitionPlayer(@NonNull TransitionController controller,
+                @NonNull WindowOrganizerController organizer) {
+            mController = controller;
+            mOrganizer = organizer;
+        }
+
+        void clear() {
+            mLastTransit = null;
+            mLastReady = null;
+            mLastRequest = null;
+        }
+
+        @Override
+        public void onTransitionReady(IBinder transitToken, TransitionInfo transitionInfo,
+                SurfaceControl.Transaction transaction) throws RemoteException {
+            mLastTransit = Transition.fromBinder(transitToken);
+            mLastReady = transitionInfo;
+        }
+
+        @Override
+        public void requestStartTransition(IBinder transitToken,
+                TransitionRequestInfo request) throws RemoteException {
+            mLastTransit = Transition.fromBinder(transitToken);
+            mLastRequest = request;
+        }
+
+        public void start() {
+            mOrganizer.startTransition(mLastRequest.getType(), mLastTransit, null);
+            mLastTransit.onTransactionReady(mLastTransit.getSyncId(),
+                    mock(SurfaceControl.Transaction.class));
+        }
+
+        public void finish() {
+            mController.finishTransition(mLastTransit);
+        }
+    }
 }
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
index c53c95c..d6c0469 100644
--- a/services/usb/java/com/android/server/usb/UsbPortManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPortManager.java
@@ -60,9 +60,9 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.service.ServiceProtoEnums;
 import android.service.usb.UsbPortInfoProto;
 import android.service.usb.UsbPortManagerProto;
-import android.service.usb.UsbServiceProto;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Slog;
@@ -1061,15 +1061,15 @@
     private static int convertContaminantDetectionStatusToProto(int contaminantDetectionStatus) {
         switch (contaminantDetectionStatus) {
             case UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED:
-                return UsbServiceProto.CONTAMINANT_STATUS_NOT_SUPPORTED;
+                return ServiceProtoEnums.CONTAMINANT_STATUS_NOT_SUPPORTED;
             case UsbPortStatus.CONTAMINANT_DETECTION_DISABLED:
-                return UsbServiceProto.CONTAMINANT_STATUS_DISABLED;
+                return ServiceProtoEnums.CONTAMINANT_STATUS_DISABLED;
             case UsbPortStatus.CONTAMINANT_DETECTION_NOT_DETECTED:
-                return UsbServiceProto.CONTAMINANT_STATUS_NOT_DETECTED;
+                return ServiceProtoEnums.CONTAMINANT_STATUS_NOT_DETECTED;
             case UsbPortStatus.CONTAMINANT_DETECTION_DETECTED:
-                return UsbServiceProto.CONTAMINANT_STATUS_DETECTED;
+                return ServiceProtoEnums.CONTAMINANT_STATUS_DETECTED;
             default:
-                return UsbServiceProto.CONTAMINANT_STATUS_UNKNOWN;
+                return ServiceProtoEnums.CONTAMINANT_STATUS_UNKNOWN;
         }
     }
 
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 2626bfd..80d4f8f 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -985,6 +985,7 @@
         @Override
         public void setHotwordDetectionServiceConfig(@Nullable Bundle options,
                 @Nullable SharedMemory sharedMemory) {
+            enforceCallingPermission(Manifest.permission.MANAGE_HOTWORD_DETECTION);
             synchronized (this) {
                 enforceIsCurrentVoiceInteractionService();
 
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 5861610..05573f1 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -50,6 +50,7 @@
 import android.service.voice.VoiceInteractionService;
 import android.service.voice.VoiceInteractionServiceInfo;
 import android.system.OsConstants;
+import android.util.Pair;
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
 import android.view.IWindowManager;
@@ -186,17 +187,27 @@
                     mSessionComponentName, mUser, mContext, this,
                     mInfo.getServiceInfo().applicationInfo.uid, mHandler);
         }
-        List<IBinder> activityTokens = null;
+        List<Pair<IBinder, Integer>> allVisibleActivities =
+                LocalServices.getService(ActivityTaskManagerInternal.class)
+                        .getTopVisibleActivities();
+
+        List<Pair<IBinder, Integer>> visibleActivities = null;
         if (activityToken != null) {
-            activityTokens = new ArrayList<>();
-            activityTokens.add(activityToken);
+            visibleActivities = new ArrayList();
+            int activitiesCount = allVisibleActivities.size();
+            for (int i = 0; i < activitiesCount; i++) {
+                if (allVisibleActivities.get(i).first == activityToken) {
+                    visibleActivities.add(
+                            new Pair<>(activityToken, allVisibleActivities.get(i).second));
+                    break;
+                }
+            }
         } else {
-            // Let's get top activities from all visible stacks
-            activityTokens = LocalServices.getService(ActivityTaskManagerInternal.class)
+            visibleActivities = LocalServices.getService(ActivityTaskManagerInternal.class)
                     .getTopVisibleActivities();
         }
         return mActiveSession.showLocked(args, flags, mDisabledShowContext, showCallback,
-                activityTokens);
+                visibleActivities);
     }
 
     public void getActiveServiceSupportedActions(List<String> commands,
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index 84f4f6a..428d342 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -56,6 +56,7 @@
 import android.service.voice.IVoiceInteractionSessionService;
 import android.service.voice.VoiceInteractionService;
 import android.service.voice.VoiceInteractionSession;
+import android.util.Pair;
 import android.util.Slog;
 import android.view.IWindowManager;
 
@@ -190,7 +191,8 @@
     }
 
     public boolean showLocked(Bundle args, int flags, int disabledContext,
-            IVoiceInteractionSessionShowCallback showCallback, List<IBinder> topActivities) {
+            IVoiceInteractionSessionShowCallback showCallback,
+            List<Pair<IBinder, Integer>> topActivities) {
         if (mBound) {
             if (!mFullyBound) {
                 mFullyBound = mContext.bindServiceAsUser(mBindIntent, mFullConnection,
@@ -205,17 +207,29 @@
             mShowFlags = flags;
 
             disabledContext |= getUserDisabledShowContextLocked();
-            mAssistDataRequester.requestAssistData(topActivities,
-                    (flags & VoiceInteractionSession.SHOW_WITH_ASSIST) != 0,
-                    (flags & VoiceInteractionSession.SHOW_WITH_SCREENSHOT) != 0,
-                    (disabledContext & VoiceInteractionSession.SHOW_WITH_ASSIST) == 0,
-                    (disabledContext & VoiceInteractionSession.SHOW_WITH_SCREENSHOT) == 0,
-                    mCallingUid, mSessionComponentName.getPackageName());
 
-            boolean needDisclosure = mAssistDataRequester.getPendingDataCount() > 0
-                    || mAssistDataRequester.getPendingScreenshotCount() > 0;
-            if (needDisclosure && AssistUtils.shouldDisclose(mContext, mSessionComponentName)) {
-                mHandler.post(mShowAssistDisclosureRunnable);
+            boolean fetchData = (flags & VoiceInteractionSession.SHOW_WITH_ASSIST) != 0;
+            boolean fetchScreenshot = (flags & VoiceInteractionSession.SHOW_WITH_SCREENSHOT) != 0;
+            boolean assistDataRequestNeeded = fetchData || fetchScreenshot;
+
+            if (assistDataRequestNeeded) {
+                int topActivitiesCount = topActivities.size();
+                final ArrayList<IBinder> topActivitiesToken = new ArrayList<>(topActivitiesCount);
+                for (int i = 0; i < topActivitiesCount; i++) {
+                    topActivitiesToken.add(topActivities.get(i).first);
+                }
+                mAssistDataRequester.requestAssistData(topActivitiesToken,
+                        fetchData,
+                        fetchScreenshot,
+                        (disabledContext & VoiceInteractionSession.SHOW_WITH_ASSIST) == 0,
+                        (disabledContext & VoiceInteractionSession.SHOW_WITH_SCREENSHOT) == 0,
+                        mCallingUid, mSessionComponentName.getPackageName());
+
+                boolean needDisclosure = mAssistDataRequester.getPendingDataCount() > 0
+                        || mAssistDataRequester.getPendingScreenshotCount() > 0;
+                if (needDisclosure && AssistUtils.shouldDisclose(mContext, mSessionComponentName)) {
+                    mHandler.post(mShowAssistDisclosureRunnable);
+                }
             }
             if (mSession != null) {
                 try {
@@ -224,7 +238,11 @@
                     mShowFlags = 0;
                 } catch (RemoteException e) {
                 }
-                mAssistDataRequester.processPendingAssistData();
+                if (assistDataRequestNeeded) {
+                    mAssistDataRequester.processPendingAssistData();
+                } else {
+                    doHandleAssistWithoutData(topActivities);
+                }
             } else if (showCallback != null) {
                 mPendingShowCallbacks.add(showCallback);
             }
@@ -240,6 +258,28 @@
         return false;
     }
 
+    private void doHandleAssistWithoutData(List<Pair<IBinder, Integer>> topActivities) {
+        final int activityCount = topActivities.size();
+        for (int i = 0; i < activityCount; i++) {
+            final Pair<IBinder, Integer> topActivity = topActivities.get(i);
+            final IBinder activityId = topActivity.first;
+            final int taskId = topActivity.second;
+            final int activityIndex = i;
+            try {
+                mSession.handleAssist(
+                        taskId,
+                        activityId,
+                        /* assistData = */ null,
+                        /* assistStructure = */ null,
+                        /* assistContent = */ null,
+                        activityIndex,
+                        activityCount);
+            } catch (RemoteException e) {
+                // Ignore
+            }
+        }
+    }
+
     @Override
     public boolean canHandleReceivedAssistDataLocked() {
         return mSession != null;
diff --git a/telecomm/java/android/telecom/CallDiagnosticService.java b/telecomm/java/android/telecom/CallDiagnosticService.java
index f5357b1..011dc17 100644
--- a/telecomm/java/android/telecom/CallDiagnosticService.java
+++ b/telecomm/java/android/telecom/CallDiagnosticService.java
@@ -27,6 +27,8 @@
 import android.os.HandlerExecutor;
 import android.os.IBinder;
 import android.os.RemoteException;
+
+import android.telephony.CallQuality;
 import android.util.ArrayMap;
 
 import com.android.internal.telecom.ICallDiagnosticService;
@@ -111,6 +113,12 @@
                 @NonNull DisconnectCause disconnectCause) throws RemoteException {
             handleCallDisconnected(callId, disconnectCause);
         }
+
+        @Override
+        public void callQualityChanged(String callId, CallQuality callQuality)
+                throws RemoteException {
+            handleCallQualityChanged(callId, callQuality);
+        }
     }
 
     /**
@@ -375,6 +383,21 @@
     }
 
     /**
+     * Handles a change reported by Telecom to the call quality for a call.
+     * @param callId the call ID the change applies to.
+     * @param callQuality The new call quality.
+     */
+    private void handleCallQualityChanged(@NonNull String callId,
+            @NonNull CallQuality callQuality) {
+        Log.i(this, "handleCallQualityChanged; call=%s, cq=%s", callId, callQuality);
+        CallDiagnostics callDiagnostics;
+        callDiagnostics = mDiagnosticCallByTelecomCallId.get(callId);
+        if (callDiagnostics != null) {
+            callDiagnostics.onCallQualityReceived(callQuality);
+        }
+    }
+
+    /**
      * Handles a request from a {@link CallDiagnostics} to send a device to device message (received
      * via {@link CallDiagnostics#sendDeviceToDeviceMessage(int, int)}.
      * @param callDiagnostics
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 6dab6df..2dc18e8 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -44,6 +44,7 @@
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.telephony.CallQuality;
 import android.telephony.ims.ImsStreamMediaProfile;
 import android.util.ArraySet;
 import android.view.Surface;
@@ -978,6 +979,23 @@
     public static final String EXTRA_DEVICE_TO_DEVICE_MESSAGE_VALUE =
             "android.telecom.extra.DEVICE_TO_DEVICE_MESSAGE_VALUE";
 
+    /**
+     * Connection event used to communicate a {@link android.telephony.CallQuality} report from
+     * telephony to Telecom for relaying to
+     * {@link DiagnosticCall#onCallQualityReceived(CallQuality)}.
+     * @hide
+     */
+    public static final String EVENT_CALL_QUALITY_REPORT =
+            "android.telecom.event.CALL_QUALITY_REPORT";
+
+    /**
+     * Extra sent with {@link #EVENT_CALL_QUALITY_REPORT} containing the
+     * {@link android.telephony.CallQuality} data.
+     * @hide
+     */
+    public static final String EXTRA_CALL_QUALITY_REPORT =
+            "android.telecom.extra.CALL_QUALITY_REPORT";
+
     // Flag controlling whether PII is emitted into the logs
     private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG);
 
diff --git a/telecomm/java/com/android/internal/telecom/ICallDiagnosticService.aidl b/telecomm/java/com/android/internal/telecom/ICallDiagnosticService.aidl
index fc9879a..4bd369f 100644
--- a/telecomm/java/com/android/internal/telecom/ICallDiagnosticService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallDiagnosticService.aidl
@@ -20,6 +20,7 @@
 import android.telecom.CallAudioState;
 import android.telecom.DisconnectCause;
 import android.telecom.ParcelableCall;
+import android.telephony.CallQuality;
 import com.android.internal.telecom.ICallDiagnosticServiceAdapter;
 
 /**
@@ -34,6 +35,7 @@
     void updateCallAudioState(in CallAudioState callAudioState);
     void removeDiagnosticCall(in String callId);
     void receiveDeviceToDeviceMessage(in String callId, int message, int value);
+    void callQualityChanged(in String callId, in CallQuality callQuality);
     void receiveBluetoothCallQualityReport(in BluetoothCallQualityReport qualityReport);
     void notifyCallDisconnected(in String callId, in DisconnectCause disconnectCause);
 }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 47fbe13..04a0aba 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -44,8 +44,6 @@
 import com.android.internal.telephony.ICarrierConfigLoader;
 import com.android.telephony.Rlog;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -116,31 +114,17 @@
      */
     public static final int USSD_OVER_IMS_ONLY       = 3;
 
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = { "CARRIER_NR_AVAILABILITY_" }, value = {
-            CARRIER_NR_AVAILABILITY_NONE,
-            CARRIER_NR_AVAILABILITY_NSA,
-            CARRIER_NR_AVAILABILITY_SA,
-    })
-    public @interface DeviceNrCapability {}
-
-    /**
-     * Indicates CARRIER_NR_AVAILABILITY_NONE determine that the carrier does not enable 5G NR.
-     */
-    public static final int CARRIER_NR_AVAILABILITY_NONE = 0;
-
     /**
      * Indicates CARRIER_NR_AVAILABILITY_NSA determine that the carrier enable the non-standalone
      * (NSA) mode of 5G NR.
      */
-    public static final int CARRIER_NR_AVAILABILITY_NSA = 1 << 0;
+    public static final int CARRIER_NR_AVAILABILITY_NSA = 1;
 
     /**
      * Indicates CARRIER_NR_AVAILABILITY_SA determine that the carrier enable the standalone (SA)
      * mode of 5G NR.
      */
-    public static final int CARRIER_NR_AVAILABILITY_SA = 1 << 1;
+    public static final int CARRIER_NR_AVAILABILITY_SA = 2;
 
     private final Context mContext;
 
@@ -1882,23 +1866,20 @@
             "show_precise_failed_cause_bool";
 
     /**
-     * Bit-field integer to determine whether the carrier enable the non-standalone (NSA) mode of
-     * 5G NR, standalone (SA) mode of 5G NR
+     * A list of carrier nr availability is used to determine whether the carrier enable the
+     * non-standalone (NSA) mode of 5G NR, standalone (SA) mode of 5G NR
      *
-     * <UL>
-     *  <LI>CARRIER_NR_AVAILABILITY_NONE: non-NR = 0 </LI>
-     *  <LI>CARRIER_NR_AVAILABILITY_NSA: NSA = 1 << 0</LI>
-     *  <LI>CARRIER_NR_AVAILABILITY_SA: SA = 1 << 1</LI>
-     * </UL>
-     * <p> The value of this key must be bitwise OR of
-     * {@link #CARRIER_NR_AVAILABILITY_NONE}, {@link #CARRIER_NR_AVAILABILITY_NSA},
-     * {@link #CARRIER_NR_AVAILABILITY_SA}.
+     * <p> The value of list is
+     * {@link #CARRIER_NR_AVAILABILITY_NSA}, or {@link #CARRIER_NR_AVAILABILITY_SA}.
      *
-     * <p> For example, if both NSA and SA are used, the value of key is 3 (1 << 0 | 1 << 1).
-     * If the carrier doesn't support 5G NR, the value of key is 0 (non-NR).
-     * If the key is invalid or not configured, a default value 3 (NSA|SA = 3) will apply.
+     * <p> For example, if both NSA and SA are used, the list value is {
+     * {@link #CARRIER_NR_AVAILABILITY_NSA},{@link #CARRIER_NR_AVAILABILITY_SA}}.
+     * If the carrier doesn't support 5G NR, the value is the empty array.
+     * If the key is invalid or not configured, the default value {
+     * {@link #CARRIER_NR_AVAILABILITY_NSA},{@link #CARRIER_NR_AVAILABILITY_SA}} will apply.
      */
-    public static final String KEY_CARRIER_NR_AVAILABILITY_INT = "carrier_nr_availability_int";
+    public static final String KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY =
+            "carrier_nr_availabilities_int_array";
 
     /**
      * Boolean to decide whether LTE is enabled.
@@ -3784,13 +3765,64 @@
         /** Prefix of all ImsServiceEntitlement.KEY_* constants. */
         public static final String KEY_PREFIX = "imsserviceentitlement.";
 
-        /** The address of the entitlement configuration server. */
+        /**
+         * The address of the entitlement configuration server.
+         *
+         * Reference: GSMA TS.43-v5, section 2.1 Default Entitlement Configuration Server.
+         */
         public static final String KEY_ENTITLEMENT_SERVER_URL_STRING =
                 KEY_PREFIX + "entitlement_server_url_string";
 
+        /**
+         * For some carriers, end-users may be presented with a web portal of the carrier before
+         * being allowed to use the VoWiFi service.
+         * To support this feature, the app hosts a {@link android.webkit.WebView} in the foreground
+         * VoWiFi entitlement configuration flow to show the web portal.
+         *
+         * {@code true} - show the VoWiFi portal in a webview.
+         *
+         * Note: this is effective only if the {@link #KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING}
+         * is set to this app.
+         *
+         * Reference: GSMA TS.43-v5, section 3, VoWiFi entitlement configuration.
+         */
+        public static final String KEY_SHOW_VOWIFI_WEBVIEW_BOOL =
+                KEY_PREFIX + "show_vowifi_webview_bool";
+
+        /**
+         * For some carriers, the network is not provisioned by default to support
+         * IMS (VoLTE/VoWiFi/SMSoIP) service for all end users. Some type of network-side
+         * provisioning must then take place before offering the IMS service to the end-user.
+         *
+         * {@code true} - need this ImsServiceEntitlement app to do IMS (VoLTE/VoWiFi/SMSoIP)
+         * provisioning in the background before offering the IMS service to the end-user.
+         *
+         * Note: this is effective only if the carrier needs IMS provisioning, i.e.
+         * {@link #KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL} is set to true.
+         *
+         * Reference: GSMA TS.43-v5, section 3 - 5, VoWiFi/VoLTE/SMSoIP entitlement configuration.
+         */
+        public static final String KEY_IMS_PROVISIONING_BOOL = KEY_PREFIX + "ims_provisioning_bool";
+
+        /**
+         * The FCM sender ID for the carrier.
+         * Used to trigger a carrier network requested entitlement configuration
+         * via Firebase Cloud Messaging (FCM). Do not set if the carrier doesn't use FCM for network
+         * requested entitlement configuration.
+         *
+         * Reference: GSMA TS.43-v5, section 2.4, Network Requested Entitlement Configuration.
+         *
+         * @see <a href="https://firebase.google.com/docs/cloud-messaging/concept-options#senderid">
+         *     About FCM messages - Credentials</a>
+         */
+        public static final String KEY_FCM_SENDER_ID_STRING = KEY_PREFIX + "fcm_sender_id_string";
+
         private static PersistableBundle getDefaults() {
             PersistableBundle defaults = new PersistableBundle();
             defaults.putString(KEY_ENTITLEMENT_SERVER_URL_STRING, "");
+            defaults.putString(KEY_FCM_SENDER_ID_STRING, "");
+            defaults.putBoolean(KEY_SHOW_VOWIFI_WEBVIEW_BOOL, false);
+            defaults.putBoolean(KEY_IMS_PROVISIONING_BOOL, false);
             return defaults;
         }
     }
@@ -4077,6 +4109,22 @@
             "is_opportunistic_subscription_bool";
 
     /**
+     * The flatten string {@link android.content.ComponentName componentName} of carrier
+     * provisioning app receiver.
+     *
+     * <p>
+     * The RadioInfo activity(*#*#INFO#*#*) will broadcast an intent to this receiver when the
+     * "Carrier Provisioning Info" or "Trigger Carrier Provisioning" button clicked.
+     *
+     * <p>
+     * e.g, com.google.android.carrierPackageName/.CarrierReceiverName
+     *
+     * @hide
+     */
+    public static final String KEY_CARRIER_PROVISIONING_APP_STRING =
+            "carrier_provisioning_app_string";
+
+    /**
      * Configs used by the IMS stack.
      */
     public static final class Ims {
@@ -5183,8 +5231,8 @@
         sDefaults.putString(KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING, "");
         sDefaults.putBoolean(KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL, true);
         sDefaults.putInt(KEY_LTE_PLUS_THRESHOLD_BANDWIDTH_KHZ_INT, 20000);
-        sDefaults.putInt(KEY_CARRIER_NR_AVAILABILITY_INT,
-                CARRIER_NR_AVAILABILITY_NSA | CARRIER_NR_AVAILABILITY_SA);
+        sDefaults.putIntArray(KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY,
+                new int[]{CARRIER_NR_AVAILABILITY_NSA, CARRIER_NR_AVAILABILITY_SA});
         sDefaults.putBoolean(KEY_LTE_ENABLED_BOOL, true);
         sDefaults.putBoolean(KEY_SUPPORT_TDSCDMA_BOOL, false);
         sDefaults.putStringArray(KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY, null);
@@ -5374,6 +5422,7 @@
         sDefaults.putStringArray(KEY_ALLOWED_INITIAL_ATTACH_APN_TYPES_STRING_ARRAY,
                 new String[]{"ia", "default", "ims", "mms", "dun", "emergency"});
         sDefaults.putBoolean(KEY_CARRIER_PROVISIONS_WIFI_MERGED_NETWORKS_BOOL, false);
+        sDefaults.putString(KEY_CARRIER_PROVISIONING_APP_STRING, "");
     }
 
     /**
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 4926687..17af463 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -19,6 +19,7 @@
 import android.Manifest;
 import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -2207,7 +2208,9 @@
      *
      * @return the total number of SMS records which can be stored on the SIM card.
      */
-    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    @RequiresPermission(anyOf = {android.Manifest.permission.READ_PHONE_STATE,
+            android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE})
+    @IntRange(from = 0)
     public int getSmsCapacityOnIcc() {
         int ret = 0;
         try {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 962200b..5a94a8a 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -15100,6 +15100,11 @@
      */
     public void registerTelephonyCallback(@NonNull @CallbackExecutor Executor executor,
             @NonNull TelephonyCallback callback) {
+
+        if (mContext == null) {
+            throw new IllegalStateException("telephony service is null.");
+        }
+
         if (executor == null || callback == null) {
             throw new IllegalArgumentException("TelephonyCallback and executor must be non-null");
         }
diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java
index ffe5399..ef02589 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -139,7 +139,7 @@
     private final int mPduSessionId;
     private final Qos mDefaultQos;
     private final List<QosBearerSession> mQosBearerSessions;
-    private final SliceInfo mSliceInfo;
+    private final NetworkSliceInfo mSliceInfo;
     private final List<TrafficDescriptor> mTrafficDescriptors;
 
     /**
@@ -202,7 +202,8 @@
             @Nullable List<InetAddress> pcscfAddresses, int mtu, int mtuV4, int mtuV6,
             @HandoverFailureMode int handoverFailureMode, int pduSessionId,
             @Nullable Qos defaultQos, @Nullable List<QosBearerSession> qosBearerSessions,
-            @Nullable SliceInfo sliceInfo, @Nullable List<TrafficDescriptor> trafficDescriptors) {
+            @Nullable NetworkSliceInfo sliceInfo,
+            @Nullable List<TrafficDescriptor> trafficDescriptors) {
         mCause = cause;
         mSuggestedRetryTime = suggestedRetryTime;
         mId = id;
@@ -255,7 +256,7 @@
         mDefaultQos = source.readParcelable(Qos.class.getClassLoader());
         mQosBearerSessions = new ArrayList<>();
         source.readList(mQosBearerSessions, QosBearerSession.class.getClassLoader());
-        mSliceInfo = source.readParcelable(SliceInfo.class.getClassLoader());
+        mSliceInfo = source.readParcelable(NetworkSliceInfo.class.getClassLoader());
         mTrafficDescriptors = new ArrayList<>();
         source.readList(mTrafficDescriptors, TrafficDescriptor.class.getClassLoader());
     }
@@ -410,7 +411,7 @@
      * @return The slice info related to this data connection.
      */
     @Nullable
-    public SliceInfo getSliceInfo() {
+    public NetworkSliceInfo getSliceInfo() {
         return mSliceInfo;
     }
 
@@ -626,7 +627,7 @@
 
         private List<QosBearerSession> mQosBearerSessions = new ArrayList<>();
 
-        private SliceInfo mSliceInfo;
+        private NetworkSliceInfo mSliceInfo;
 
         private List<TrafficDescriptor> mTrafficDescriptors = new ArrayList<>();
 
@@ -865,13 +866,13 @@
          * The Slice used for this data connection.
          * <p/>
          * If a handover occurs from EPDG to 5G,
-         * this is the {@link SliceInfo} used in {@link DataService#setupDataCall}.
+         * this is the {@link NetworkSliceInfo} used in {@link DataService#setupDataCall}.
          *
          * @param sliceInfo the slice info for the data call
          *
          * @return The same instance of the builder.
          */
-        public @NonNull Builder setSliceInfo(@Nullable SliceInfo sliceInfo) {
+        public @NonNull Builder setSliceInfo(@Nullable NetworkSliceInfo sliceInfo) {
             mSliceInfo = sliceInfo;
             return this;
         }
diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java
index 048b329..2f03475 100644
--- a/telephony/java/android/telephony/data/DataService.java
+++ b/telephony/java/android/telephony/data/DataService.java
@@ -218,7 +218,7 @@
                 boolean isRoaming, boolean allowRoaming,
                 @SetupDataReason int reason,
                 @Nullable LinkProperties linkProperties,
-                @IntRange(from = 0, to = 15) int pduSessionId, @Nullable SliceInfo sliceInfo,
+                @IntRange(from = 0, to = 15) int pduSessionId, @Nullable NetworkSliceInfo sliceInfo,
                 @Nullable TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed,
                 @NonNull DataServiceCallback callback) {
             /* Call the old version since the new version isn't supported */
@@ -418,13 +418,13 @@
         public final int reason;
         public final LinkProperties linkProperties;
         public final int pduSessionId;
-        public final SliceInfo sliceInfo;
+        public final NetworkSliceInfo sliceInfo;
         public final TrafficDescriptor trafficDescriptor;
         public final boolean matchAllRuleAllowed;
         public final IDataServiceCallback callback;
         SetupDataCallRequest(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
                 boolean allowRoaming, int reason, LinkProperties linkProperties, int pduSessionId,
-                SliceInfo sliceInfo, TrafficDescriptor trafficDescriptor,
+                NetworkSliceInfo sliceInfo, TrafficDescriptor trafficDescriptor,
                 boolean matchAllRuleAllowed, IDataServiceCallback callback) {
             this.accessNetworkType = accessNetworkType;
             this.dataProfile = dataProfile;
@@ -711,7 +711,7 @@
         @Override
         public void setupDataCall(int slotIndex, int accessNetworkType, DataProfile dataProfile,
                 boolean isRoaming, boolean allowRoaming, int reason,
-                LinkProperties linkProperties, int pduSessionId, SliceInfo sliceInfo,
+                LinkProperties linkProperties, int pduSessionId, NetworkSliceInfo sliceInfo,
                 TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed,
                 IDataServiceCallback callback) {
             mHandler.obtainMessage(DATA_SERVICE_REQUEST_SETUP_DATA_CALL, slotIndex, 0,
diff --git a/telephony/java/android/telephony/data/IDataService.aidl b/telephony/java/android/telephony/data/IDataService.aidl
index 81f5fd3..1346946 100644
--- a/telephony/java/android/telephony/data/IDataService.aidl
+++ b/telephony/java/android/telephony/data/IDataService.aidl
@@ -19,7 +19,7 @@
 import android.net.LinkProperties;
 import android.telephony.data.DataProfile;
 import android.telephony.data.IDataServiceCallback;
-import android.telephony.data.SliceInfo;
+import android.telephony.data.NetworkSliceInfo;
 import android.telephony.data.TrafficDescriptor;
 
 /**
@@ -31,7 +31,7 @@
     void removeDataServiceProvider(int slotId);
     void setupDataCall(int slotId, int accessNetwork, in DataProfile dataProfile, boolean isRoaming,
                        boolean allowRoaming, int reason, in LinkProperties linkProperties,
-                       int pduSessionId, in SliceInfo sliceInfo,
+                       int pduSessionId, in NetworkSliceInfo sliceInfo,
                        in TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed,
                        IDataServiceCallback callback);
     void deactivateDataCall(int slotId, int cid, int reason, IDataServiceCallback callback);
diff --git a/telephony/java/android/telephony/data/SliceInfo.aidl b/telephony/java/android/telephony/data/NetworkSliceInfo.aidl
similarity index 95%
rename from telephony/java/android/telephony/data/SliceInfo.aidl
rename to telephony/java/android/telephony/data/NetworkSliceInfo.aidl
index 286ea5e..e1a11f2 100644
--- a/telephony/java/android/telephony/data/SliceInfo.aidl
+++ b/telephony/java/android/telephony/data/NetworkSliceInfo.aidl
@@ -17,4 +17,4 @@
 /** @hide */
 package android.telephony.data;
 
-parcelable SliceInfo;
+parcelable NetworkSliceInfo;
diff --git a/telephony/java/android/telephony/data/SliceInfo.java b/telephony/java/android/telephony/data/NetworkSliceInfo.java
similarity index 88%
rename from telephony/java/android/telephony/data/SliceInfo.java
rename to telephony/java/android/telephony/data/NetworkSliceInfo.java
index 51857a7..1d90095 100644
--- a/telephony/java/android/telephony/data/SliceInfo.java
+++ b/telephony/java/android/telephony/data/NetworkSliceInfo.java
@@ -29,12 +29,17 @@
 import java.util.Objects;
 
 /**
- * Represents a S-NSSAI as defined in 3GPP TS 24.501.
+ * Represents a S-NSSAI as defined in 3GPP TS 24.501, which represents a network slice.
+ *
+ * There are 2 main fields that define a slice, SliceServiceType and SliceDifferentiator.
+ * SliceServiceType defines the type of service provided by the slice, and SliceDifferentiator is
+ * used to differentiate between multiple slices of the same type. If the devices is not on HPLMN,
+ * the mappedHplmn versions of these 2 fields indicate the corresponding values in HPLMN.
  *
  * @hide
  */
 @SystemApi
-public final class SliceInfo implements Parcelable {
+public final class NetworkSliceInfo implements Parcelable {
     /**
      * When set on a Slice Differentiator, this value indicates that there is no corresponding
      * Slice.
@@ -93,7 +98,7 @@
     @IntRange(from = MIN_SLICE_DIFFERENTIATOR, to = MAX_SLICE_DIFFERENTIATOR)
     private final int mMappedHplmnSliceDifferentiator;
 
-    private SliceInfo(@SliceServiceType int sliceServiceType,
+    private NetworkSliceInfo(@SliceServiceType int sliceServiceType,
             int sliceDifferentiator, int mappedHplmnSliceServiceType,
             int mappedHplmnSliceDifferentiator) {
         mSliceServiceType = sliceServiceType;
@@ -136,7 +141,7 @@
     }
 
     /**
-     * This Slice Differentiator corresponds to a {@link SliceInfo} (S-NSSAI) of the HPLMN;
+     * This Slice Differentiator corresponds to a {@link NetworkSliceInfo} (S-NSSAI) of the HPLMN;
      * {@link #getSliceDifferentiator()} is mapped to this value.
      * <p/>
      * Returns {@link #SLICE_DIFFERENTIATOR_NO_SLICE} if either of the following are true:
@@ -152,7 +157,7 @@
         return mMappedHplmnSliceDifferentiator;
     }
 
-    private SliceInfo(@NonNull Parcel in) {
+    private NetworkSliceInfo(@NonNull Parcel in) {
         mSliceServiceType = in.readInt();
         mSliceDifferentiator = in.readInt();
         mMappedHplmnSliceServiceType = in.readInt();
@@ -172,18 +177,18 @@
         dest.writeInt(mMappedHplmnSliceDifferentiator);
     }
 
-    public static final @android.annotation.NonNull Parcelable.Creator<SliceInfo> CREATOR =
-            new Parcelable.Creator<SliceInfo>() {
+    public static final @android.annotation.NonNull Parcelable.Creator<NetworkSliceInfo> CREATOR =
+            new Parcelable.Creator<NetworkSliceInfo>() {
                 @Override
                 @NonNull
-                public SliceInfo createFromParcel(@NonNull Parcel source) {
-                    return new SliceInfo(source);
+                public NetworkSliceInfo createFromParcel(@NonNull Parcel source) {
+                    return new NetworkSliceInfo(source);
                 }
 
                 @Override
                 @NonNull
-                public SliceInfo[] newArray(int size) {
-                    return new SliceInfo[size];
+                public NetworkSliceInfo[] newArray(int size) {
+                    return new NetworkSliceInfo[size];
                 }
             };
 
@@ -217,7 +222,7 @@
     public boolean equals(Object o) {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
-        SliceInfo sliceInfo = (SliceInfo) o;
+        NetworkSliceInfo sliceInfo = (NetworkSliceInfo) o;
         return mSliceServiceType == sliceInfo.mSliceServiceType
                 && mSliceDifferentiator == sliceInfo.mSliceDifferentiator
                 && mMappedHplmnSliceServiceType == sliceInfo.mMappedHplmnSliceServiceType
@@ -231,7 +236,7 @@
     }
 
     /**
-     * Provides a convenient way to set the fields of a {@link SliceInfo} when creating a
+     * Provides a convenient way to set the fields of a {@link NetworkSliceInfo} when creating a
      * new instance.
      *
      * <p>The example below shows how you might create a new {@code SliceInfo}:
@@ -329,13 +334,13 @@
         }
 
         /**
-         * Build the {@link SliceInfo}.
+         * Build the {@link NetworkSliceInfo}.
          *
-         * @return the {@link SliceInfo} object.
+         * @return the {@link NetworkSliceInfo} object.
          */
         @NonNull
-        public SliceInfo build() {
-            return new SliceInfo(this.mSliceServiceType, this.mSliceDifferentiator,
+        public NetworkSliceInfo build() {
+            return new NetworkSliceInfo(this.mSliceServiceType, this.mSliceDifferentiator,
                     this.mMappedHplmnSliceServiceType, this.mMappedHplmnSliceDifferentiator);
         }
     }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
index d669a01..e118363 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
@@ -19,7 +19,6 @@
 import android.app.Instrumentation
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
-import androidx.test.filters.FlakyTest
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.server.wm.flicker.FlickerBuilderProvider
 import com.android.server.wm.flicker.FlickerTestParameter
@@ -38,7 +37,6 @@
 import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
 import com.android.server.wm.flicker.wallpaperLayerReplacesAppLayer
 import com.android.server.wm.flicker.wallpaperWindowBecomesVisible
-import org.junit.Assume
 import org.junit.Test
 
 abstract class CloseAppTransition(protected val testSpec: FlickerTestParameter) {
@@ -92,32 +90,16 @@
     @Presubmit
     @Test
     open fun navBarLayerRotatesAndScales() {
-        Assume.assumeFalse(testSpec.isRotated)
-        testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
-    }
-
-    @FlakyTest
-    @Test
-    open fun navBarLayerRotatesAndScales_Flaky() {
-        Assume.assumeTrue(testSpec.isRotated)
         testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
     }
 
     @Presubmit
     @Test
     open fun statusBarLayerRotatesScales() {
-        Assume.assumeFalse(testSpec.isRotated)
         testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
     }
 
-    @FlakyTest
-    @Test
-    open fun statusBarLayerRotatesScales_Flaky() {
-        Assume.assumeTrue(testSpec.isRotated)
-        testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
-    }
-
-    @FlakyTest(bugId = 173689015)
+    @Presubmit
     @Test
     open fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
         testSpec.assertWm {
@@ -125,7 +107,7 @@
         }
     }
 
-    @FlakyTest(bugId = 173689015)
+    @Presubmit
     @Test
     open fun visibleLayersShownMoreThanOneConsecutiveEntry() {
         testSpec.assertLayers {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
index aad06ee..90c2338 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
@@ -17,10 +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 android.view.WindowManagerPolicyConstants
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import androidx.test.platform.app.InstrumentationRegistry
@@ -30,19 +27,15 @@
 import com.android.server.wm.flicker.FlickerTestParameterFactory
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
 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.repetitions
 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 com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
-import org.junit.Assume
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -64,23 +57,15 @@
     @FlickerBuilderProvider
     fun buildFlicker(): FlickerBuilder {
         return FlickerBuilder(instrumentation).apply {
-            withTestName { testSpec.name }
-            repeat { testSpec.config.repetitions }
             setup {
-                test {
-                    device.wakeUpAndGoToHomeScreen()
-                }
                 eachRun {
                     testApp.launchViaIntent(wmHelper)
                     testApp.openIME(device, wmHelper)
-                    this.setRotation(testSpec.config.startRotation)
                 }
             }
             teardown {
                 test {
-                    testApp.exit()
-                    wmHelper.waitForAppTransitionIdle()
-                    this.setRotation(Surface.ROTATION_0)
+                    testApp.exit(wmHelper)
                 }
             }
             transitions {
@@ -89,15 +74,15 @@
         }
     }
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
         testSpec.assertWm {
@@ -107,60 +92,44 @@
         }
     }
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun imeAppWindowIsAlwaysVisible() = testSpec.imeAppWindowIsAlwaysVisible(testApp)
 
-    @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 imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun imeAppLayerIsAlwaysVisible() = testSpec.imeAppLayerIsAlwaysVisible(testApp)
 
-    @Presubmit
+    @FlakyTest
     @Test
     fun navBarLayerRotatesAndScales() {
-        Assume.assumeFalse(testSpec.isRotated)
         testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
     }
 
     @FlakyTest
     @Test
-    fun navBarLayerRotatesAndScales_Flaky() {
-        Assume.assumeTrue(testSpec.isRotated)
-        testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
+    fun statusBarLayerRotatesScales() {
+        testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation)
     }
 
     @Presubmit
     @Test
-    fun statusBarLayerRotatesScales() {
-        Assume.assumeFalse(testSpec.isRotated)
-        testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation)
-    }
-
-    @FlakyTest
-    @Test
-    fun statusBarLayerRotatesScales_Flaky() {
-        Assume.assumeTrue(testSpec.isRotated)
-        testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation)
-    }
-
-    @FlakyTest
-    @Test
     fun visibleLayersShownMoreThanOneConsecutiveEntry() {
         testSpec.assertLayers {
             this.visibleLayersShownMoreThanOneConsecutiveEntry()
@@ -172,12 +141,7 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(
-                    repetitions = 5,
-                    supportedNavigationModes = listOf(
-                        WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
-                    )
-                )
+                .getConfigNonRotationTests(repetitions = 5)
         }
     }
 }
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 d08e7e2e..b25bc99 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
@@ -19,7 +19,6 @@
 import android.app.Instrumentation
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
-import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import androidx.test.platform.app.InstrumentationRegistry
@@ -29,19 +28,15 @@
 import com.android.server.wm.flicker.FlickerTestParameterFactory
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
 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.repetitions
 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 com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
-import org.junit.Assume
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -63,22 +58,15 @@
     @FlickerBuilderProvider
     fun buildFlicker(): FlickerBuilder {
         return FlickerBuilder(instrumentation).apply {
-            withTestName { testSpec.name }
-            repeat { testSpec.config.repetitions }
             setup {
-                test {
-                    device.wakeUpAndGoToHomeScreen()
-                }
                 eachRun {
                     testApp.launchViaIntent(wmHelper)
                     testApp.openIME(device, wmHelper)
-                    this.setRotation(testSpec.config.startRotation)
                 }
             }
             teardown {
                 test {
-                    testApp.exit()
-                    this.setRotation(Surface.ROTATION_0)
+                    testApp.exit(wmHelper)
                 }
             }
             transitions {
@@ -128,31 +116,15 @@
     @Test
     fun imeAppLayerBecomesInvisible() = testSpec.imeAppLayerBecomesInvisible(testApp)
 
-    @Presubmit
+    @FlakyTest
     @Test
     fun navBarLayerRotatesAndScales() {
-        Assume.assumeFalse(testSpec.isRotated)
         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)
-    }
-
-    @Presubmit
-    @Test
     fun statusBarLayerRotatesScales() {
-        Assume.assumeFalse(testSpec.isRotated)
-        testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
-    }
-
-    @FlakyTest
-    @Test
-    fun statusBarLayerRotatesScales_Flaky() {
-        Assume.assumeTrue(testSpec.isRotated)
         testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
     }
 
@@ -167,17 +139,6 @@
     @Presubmit
     @Test
     fun visibleLayersShownMoreThanOneConsecutiveEntry() {
-        Assume.assumeFalse(testSpec.isRotated)
-        testSpec.assertLayers {
-            this.visibleLayersShownMoreThanOneConsecutiveEntry(
-                listOf(IME_WINDOW_TITLE, WindowManagerStateHelper.SPLASH_SCREEN_NAME))
-        }
-    }
-
-    @FlakyTest
-    @Test
-    fun visibleLayersShownMoreThanOneConsecutiveEntry_Flaky() {
-        Assume.assumeTrue(testSpec.isRotated)
         testSpec.assertLayers {
             this.visibleLayersShownMoreThanOneConsecutiveEntry(
                 listOf(IME_WINDOW_TITLE, WindowManagerStateHelper.SPLASH_SCREEN_NAME))
@@ -189,12 +150,7 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(
-                    repetitions = 5,
-                    supportedNavigationModes = listOf(
-                        WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
-                    )
-                )
+                .getConfigNonRotationTests(repetitions = 5)
         }
     }
 }
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 19dec7a..6b8bf63 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
@@ -18,8 +18,7 @@
 
 import android.app.Instrumentation
 import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.server.wm.flicker.FlickerBuilderProvider
@@ -28,16 +27,14 @@
 import com.android.server.wm.flicker.FlickerTestParameterFactory
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.ImeAppHelper
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
 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.repetitions
 import com.android.server.wm.flicker.startRotation
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
 import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import org.junit.Assume
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -60,13 +57,9 @@
     @FlickerBuilderProvider
     fun buildFlicker(): FlickerBuilder {
         return FlickerBuilder(instrumentation).apply {
-            withTestName { testSpec.name }
-            repeat { testSpec.config.repetitions }
             setup {
                 test {
-                    device.wakeUpAndGoToHomeScreen()
                     testApp.launchViaIntent()
-                    this.setRotation(testSpec.config.startRotation)
                 }
                 eachRun {
                     testApp.openIME(device, wmHelper)
@@ -74,8 +67,7 @@
             }
             teardown {
                 test {
-                    testApp.exit()
-                    this.setRotation(Surface.ROTATION_0)
+                    testApp.exit(wmHelper)
                 }
             }
             transitions {
@@ -120,13 +112,31 @@
 
     @Presubmit
     @Test
-    fun navBarLayerRotatesAndScales() =
+    fun navBarLayerRotatesAndScales() {
+        Assume.assumeFalse(testSpec.isRotated)
         testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
+    }
+
+    @FlakyTest
+    @Test
+    fun navBarLayerRotatesAndScales_Flaky() {
+        Assume.assumeTrue(testSpec.isRotated)
+        testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
+    }
 
     @Presubmit
     @Test
-    fun statusBarLayerRotatesScales() =
+    fun statusBarLayerRotatesScales() {
+        Assume.assumeFalse(testSpec.isRotated)
         testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation)
+    }
+
+    @FlakyTest
+    @Test
+    fun statusBarLayerRotatesScales_Flaky() {
+        Assume.assumeTrue(testSpec.isRotated)
+        testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation)
+    }
 
     @Presubmit
     @Test
@@ -149,12 +159,7 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(
-                    repetitions = 5,
-                    supportedNavigationModes = listOf(
-                        WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
-                    )
-                )
+                .getConfigNonRotationTests(repetitions = 5)
         }
     }
 }
\ No newline at end of file
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 b214414..9b37caf 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
@@ -20,7 +20,6 @@
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import android.view.WindowManagerPolicyConstants
-import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.server.wm.flicker.FlickerBuilderProvider
@@ -29,18 +28,14 @@
 import com.android.server.wm.flicker.FlickerTestParameterFactory
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.ImeAppHelper
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
 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.repetitions
 import com.android.server.wm.flicker.startRotation
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
 import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
-import org.junit.Assume
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -61,15 +56,9 @@
     @FlickerBuilderProvider
     fun buildFlicker(): FlickerBuilder {
         return FlickerBuilder(instrumentation).apply {
-            withTestName { testSpec.name }
-            repeat { testSpec.config.repetitions }
             setup {
-                test {
-                    device.wakeUpAndGoToHomeScreen()
-                }
                 eachRun {
                     testApp.launchViaIntent(wmHelper)
-                    this.setRotation(testSpec.config.startRotation)
                     testApp.openIME(device, wmHelper)
                 }
             }
@@ -85,7 +74,6 @@
                 }
                 test {
                     testApp.exit()
-                    this.setRotation(Surface.ROTATION_0)
                 }
             }
         }
@@ -146,18 +134,10 @@
     @Presubmit
     @Test
     fun statusBarLayerRotatesScales() {
-        Assume.assumeFalse(testSpec.isRotated)
         testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
     }
 
-    @FlakyTest
-    @Test
-    fun statusBarLayerRotatesScales_Flaky() {
-        Assume.assumeTrue(testSpec.isRotated)
-        testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
-    }
-
-    @FlakyTest
+    @Presubmit
     @Test
     fun visibleLayersShownMoreThanOneConsecutiveEntry() {
         testSpec.assertLayers {
@@ -175,6 +155,7 @@
                     repetitions = 5,
                     supportedRotations = listOf(Surface.ROTATION_0),
                     supportedNavigationModes = listOf(
+                        WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
                         WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
                     )
                 )
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 ab5e9b4..d39044ab 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
@@ -20,7 +20,6 @@
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import android.view.WindowManagerPolicyConstants
-import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.server.wm.flicker.FlickerBuilderProvider
@@ -28,8 +27,6 @@
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.FlickerTestParameterFactory
 import com.android.server.wm.flicker.helpers.ImeAppHelper
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
 import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
 import com.android.server.wm.flicker.navBarLayerRotatesAndScales
 import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
@@ -37,12 +34,10 @@
 import com.android.server.wm.flicker.appWindowAlwaysVisibleOnTop
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.layerAlwaysVisible
-import com.android.server.wm.flicker.repetitions
 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.Assume
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -64,13 +59,9 @@
     @FlickerBuilderProvider
     fun buildFlicker(): FlickerBuilder {
         return FlickerBuilder(instrumentation).apply {
-            withTestName { testSpec.name }
-            repeat { testSpec.config.repetitions }
             setup {
                 test {
-                    device.wakeUpAndGoToHomeScreen()
                     testApp.launchViaIntent(wmHelper)
-                    this.setRotation(testSpec.config.startRotation)
                 }
             }
             transitions {
@@ -82,7 +73,6 @@
                 }
                 test {
                     testApp.exit()
-                    this.setRotation(Surface.ROTATION_0)
                 }
             }
         }
@@ -127,32 +117,16 @@
     @Presubmit
     @Test
     fun navBarLayerRotatesAndScales() {
-        Assume.assumeFalse(testSpec.isRotated)
-        testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
-    }
-
-    @FlakyTest
-    @Test
-    fun navBarLayerRotatesAndScales_Flaky() {
-        Assume.assumeTrue(testSpec.isRotated)
         testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
     }
 
     @Presubmit
     @Test
     fun statusBarLayerRotatesScales() {
-        Assume.assumeFalse(testSpec.isRotated)
         testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation)
     }
 
-    @FlakyTest
-    @Test
-    fun statusBarLayerRotatesScales_Flaky() {
-        Assume.assumeTrue(testSpec.isRotated)
-        testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation)
-    }
-
-    @FlakyTest
+    @Presubmit
     @Test
     fun visibleLayersShownMoreThanOneConsecutiveEntry() {
         testSpec.assertLayers {
@@ -160,7 +134,7 @@
         }
     }
 
-    @FlakyTest
+    @Presubmit
     @Test
     fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
         testSpec.assertWm {
@@ -177,6 +151,7 @@
                     repetitions = 5,
                     supportedRotations = listOf(Surface.ROTATION_0),
                     supportedNavigationModes = listOf(
+                        WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
                         WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
                     )
                 )
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
index 52a8266..95b1d3c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
@@ -30,7 +30,6 @@
 import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
 import com.android.server.wm.flicker.helpers.reopenAppFromOverview
 import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
 import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
 import com.android.server.wm.flicker.navBarLayerRotatesAndScales
 import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
@@ -38,14 +37,12 @@
 import com.android.server.wm.flicker.appLayerReplacesWallpaperLayer
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.noUncoveredRegions
-import com.android.server.wm.flicker.repetitions
 import com.android.server.wm.flicker.startRotation
 import com.android.server.wm.flicker.endRotation
 import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
 import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
 import com.android.server.wm.flicker.testapp.ActivityOptions
-import org.junit.Assume
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -68,11 +65,8 @@
     @FlickerBuilderProvider
     fun buildFlicker(): FlickerBuilder {
         return FlickerBuilder(instrumentation).apply {
-            withTestName { testSpec.name }
-            repeat { testSpec.config.repetitions }
             setup {
                 test {
-                    device.wakeUpAndGoToHomeScreen()
                     testApp.launchViaIntent(wmHelper)
                     testApp.openIME(device, wmHelper)
                 }
@@ -89,7 +83,6 @@
             }
             teardown {
                 test {
-                    this.setRotation(Surface.ROTATION_0)
                     testApp.exit()
                 }
             }
@@ -104,7 +97,7 @@
     @Test
     fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
 
-    @Presubmit
+    @FlakyTest
     @Test
     fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
         testSpec.assertWm {
@@ -148,36 +141,20 @@
     fun appLayerReplacesWallpaperLayer() =
         testSpec.appLayerReplacesWallpaperLayer(testAppComponentName.className)
 
-    @Presubmit
+    @FlakyTest
     @Test
     fun navBarLayerRotatesAndScales() {
-        Assume.assumeFalse(testSpec.isRotated)
         testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation)
     }
 
     @FlakyTest
     @Test
-    fun navBarLayerRotatesAndScales_Flaky() {
-        Assume.assumeTrue(testSpec.isRotated)
-        testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation)
+    fun statusBarLayerRotatesScales() {
+        testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0, testSpec.config.endRotation)
     }
 
     @Presubmit
     @Test
-    fun statusBarLayerRotatesScales() {
-        Assume.assumeFalse(testSpec.isRotated)
-        testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0, testSpec.config.endRotation)
-    }
-
-    @FlakyTest
-    @Test
-    fun statusBarLayerRotatesScales_Flaky() {
-        Assume.assumeTrue(testSpec.isRotated)
-        testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0, testSpec.config.endRotation)
-    }
-
-    @FlakyTest
-    @Test
     fun visibleLayersShownMoreThanOneConsecutiveEntry() {
         testSpec.assertLayers {
             this.visibleLayersShownMoreThanOneConsecutiveEntry()
@@ -192,6 +169,7 @@
                 .getConfigNonRotationTests(
                     repetitions = 1,
                     supportedNavigationModes = listOf(
+                        WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
                         WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
                     )
                 )
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 2e59dac..a19a95d 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
@@ -16,7 +16,7 @@
 
 package com.android.server.wm.flicker.launch
 
-import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.Postsubmit
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -27,7 +27,6 @@
 import com.android.server.wm.flicker.startRotation
 import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible
 import com.android.server.wm.flicker.dsl.FlickerBuilder
-import org.junit.Assume
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -64,69 +63,21 @@
             }
         }
 
+    @Postsubmit
     @Test
     override fun appWindowReplacesLauncherAsTopWindow() =
         super.appWindowReplacesLauncherAsTopWindow()
 
+    @Postsubmit
     @Test
     override fun wallpaperWindowBecomesInvisible() {
         testSpec.wallpaperWindowBecomesInvisible()
     }
 
-    @Presubmit
-    @Test
-    override fun statusBarLayerIsAlwaysVisible() {
-        Assume.assumeTrue(testSpec.isRotated)
-        super.statusBarLayerIsAlwaysVisible()
-    }
-
-    @Presubmit
-    @Test
-    override fun navBarLayerIsAlwaysVisible() {
-        Assume.assumeTrue(testSpec.isRotated)
-        super.navBarLayerIsAlwaysVisible()
-    }
-
     @FlakyTest
     @Test
-    fun statusBarLayerIsAlwaysVisible_Flaky() {
-        Assume.assumeFalse(testSpec.isRotated)
-        super.statusBarLayerIsAlwaysVisible()
-    }
-
-    @FlakyTest
-    @Test
-    fun navBarLayerIsAlwaysVisible_Flaky() {
-        Assume.assumeFalse(testSpec.isRotated)
-        super.navBarLayerIsAlwaysVisible()
-    }
-
-    @Presubmit
-    @Test
-    override fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
-        Assume.assumeFalse(testSpec.isRotated)
-        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-    }
-
-    @FlakyTest
-    @Test
-    fun visibleWindowsShownMoreThanOneConsecutiveEntry_Flaky() {
-        Assume.assumeTrue(testSpec.isRotated)
-        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-    }
-
-    @Presubmit
-    @Test
-    override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
-        Assume.assumeFalse(testSpec.isRotated)
-        super.visibleLayersShownMoreThanOneConsecutiveEntry()
-    }
-
-    @FlakyTest
-    @Test
-    fun visibleLayersShownMoreThanOneConsecutiveEntry_Flaky() {
-        Assume.assumeTrue(testSpec.isRotated)
-        super.visibleLayersShownMoreThanOneConsecutiveEntry()
+    override fun navBarLayerRotatesAndScales() {
+        super.navBarLayerRotatesAndScales()
     }
 
     companion object {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
index 5197f0e..cd5c61a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
@@ -19,7 +19,6 @@
 import android.app.Instrumentation
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
-import androidx.test.filters.FlakyTest
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.server.wm.flicker.FlickerBuilderProvider
 import com.android.server.wm.flicker.FlickerTestParameter
@@ -41,7 +40,6 @@
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
 import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
 import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible
-import org.junit.Assume
 import org.junit.Test
 
 abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) {
@@ -86,14 +84,6 @@
     @Presubmit
     @Test
     open fun navBarLayerRotatesAndScales() {
-        Assume.assumeFalse(testSpec.isRotated)
-        testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation)
-    }
-
-    @FlakyTest
-    @Test
-    open fun navBarLayerRotatesAndScales_Flaky() {
-        Assume.assumeTrue(testSpec.isRotated)
         testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation)
     }
 
@@ -112,14 +102,6 @@
     @Presubmit
     @Test
     open fun statusBarLayerRotatesScales() {
-        Assume.assumeFalse(testSpec.isRotated)
-        testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0, testSpec.config.endRotation)
-    }
-
-    @FlakyTest
-    @Test
-    open fun statusBarLayerRotatesScales_Flaky() {
-        Assume.assumeTrue(testSpec.isRotated)
         testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0, testSpec.config.endRotation)
     }
 
@@ -131,7 +113,7 @@
         }
     }
 
-    @FlakyTest
+    @Presubmit
     @Test
     open fun visibleLayersShownMoreThanOneConsecutiveEntry() {
         testSpec.assertLayers {
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 dee7e59..dcc64c9 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
@@ -16,7 +16,6 @@
 
 package com.android.server.wm.flicker.launch
 
-import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.FlickerTestParameter
@@ -25,7 +24,6 @@
 import com.android.server.wm.flicker.startRotation
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import org.junit.FixMethodOrder
-import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
 import org.junit.runners.Parameterized
@@ -63,11 +61,6 @@
             }
         }
 
-    @FlakyTest
-    @Test
-    override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
-        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
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 6985b36..f037f1d 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
@@ -17,12 +17,14 @@
 package com.android.server.wm.flicker.rotation
 
 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.helpers.SimpleAppHelper
+import org.junit.Assume
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -51,6 +53,26 @@
             }
         }
 
+    @FlakyTest(bugId = 151179149)
+    @Test
+    override fun focusDoesNotChange() {
+        super.focusDoesNotChange()
+    }
+
+    @Presubmit
+    @Test
+    override fun navBarLayerRotatesAndScales() {
+        Assume.assumeFalse(testSpec.isRotated)
+        super.navBarLayerRotatesAndScales()
+    }
+
+    @FlakyTest(bugId = 140855415)
+    @Test
+    fun navBarLayerRotatesAndScales_flaky() {
+        Assume.assumeTrue(testSpec.isRotated)
+        super.navBarLayerRotatesAndScales()
+    }
+
     @Presubmit
     @Test
     fun screenshotLayerBecomesInvisible() {
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 e914f64..6d2a923 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
@@ -18,7 +18,6 @@
 
 import android.app.Instrumentation
 import android.platform.test.annotations.Presubmit
-import androidx.test.filters.FlakyTest
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.server.wm.flicker.FlickerBuilderProvider
 import com.android.server.wm.flicker.FlickerTestParameter
@@ -74,13 +73,13 @@
         testSpec.navBarWindowIsAlwaysVisible()
     }
 
-    @FlakyTest(bugId = 140855415)
+    @Presubmit
     @Test
     open fun navBarLayerIsAlwaysVisible() {
         testSpec.navBarLayerIsAlwaysVisible()
     }
 
-    @FlakyTest(bugId = 140855415)
+    @Presubmit
     @Test
     open fun navBarLayerRotatesAndScales() {
         testSpec.navBarLayerRotatesAndScales(
@@ -93,20 +92,20 @@
         testSpec.statusBarWindowIsAlwaysVisible()
     }
 
-    @FlakyTest(bugId = 140855415)
+    @Presubmit
     @Test
     open fun statusBarLayerIsAlwaysVisible() {
         testSpec.statusBarLayerIsAlwaysVisible()
     }
 
-    @FlakyTest(bugId = 140855415)
+    @Presubmit
     @Test
     open fun statusBarLayerRotatesScales() {
         testSpec.statusBarLayerRotatesScales(
             testSpec.config.startRotation, testSpec.config.endRotation)
     }
 
-    @FlakyTest(bugId = 140855415)
+    @Presubmit
     @Test
     open fun visibleLayersShownMoreThanOneConsecutiveEntry() {
         testSpec.assertLayers {
@@ -129,13 +128,13 @@
             testSpec.config.endRotation, allStates = false)
     }
 
-    @FlakyTest(bugId = 151179149)
+    @Presubmit
     @Test
     open fun focusDoesNotChange() {
         testSpec.focusDoesNotChange()
     }
 
-    @FlakyTest(bugId = 140855415)
+    @Presubmit
     @Test
     open fun appLayerRotates_StartingPos() {
         testSpec.assertLayersStart {
@@ -143,7 +142,7 @@
         }
     }
 
-    @FlakyTest(bugId = 140855415)
+    @Presubmit
     @Test
     open fun appLayerRotates_EndingPos() {
         testSpec.assertLayersEnd {
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 45d3006..fe444bd 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
@@ -22,7 +22,6 @@
 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.appWindowAlwaysVisibleOnTop
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.SeamlessRotationAppHelper
 import com.android.server.wm.flicker.layerAlwaysVisible
@@ -61,26 +60,24 @@
 
     @FlakyTest(bugId = 140855415)
     @Test
-    override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
+    override fun navBarLayerRotatesAndScales() {
+        super.navBarLayerRotatesAndScales()
+    }
 
     @FlakyTest(bugId = 140855415)
     @Test
-    override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
-
-    @FlakyTest(bugId = 147659548)
-    @Test
-    override fun noUncoveredRegions() = super.noUncoveredRegions()
+    override fun statusBarLayerRotatesScales() {
+        super.statusBarLayerRotatesScales()
+    }
 
     @Presubmit
     @Test
-    fun appWindowAlwaysVisibleOnTop() = testSpec.appWindowAlwaysVisibleOnTop(testApp.`package`)
+    fun appLayerAlwaysVisible() {
+        testSpec.layerAlwaysVisible(testApp.`package`)
+    }
 
     @Presubmit
     @Test
-    fun layerAlwaysVisible() = testSpec.layerAlwaysVisible(testApp.`package`)
-
-    @FlakyTest(bugId = 147659548)
-    @Test
     fun appLayerRotates() {
         testSpec.assertLayers {
             this.coversExactly(startingPos, testApp.`package`)
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/EdgeEffectStretchActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/EdgeEffectStretchActivity.java
index f0e6299..c4b0072 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/EdgeEffectStretchActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/EdgeEffectStretchActivity.java
@@ -18,8 +18,6 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.widget.HorizontalScrollView;
-import android.widget.ScrollView;
 
 public class EdgeEffectStretchActivity extends Activity {
 
@@ -27,10 +25,5 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.stretch_layout);
-        HorizontalScrollView hsv = findViewById(R.id.horizontal_scroll_view);
-        hsv.setStretchDistance(50f);
-
-        ScrollView sv = findViewById(R.id.scroll_view);
-        sv.setStretchDistance(50f);
     }
 }
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PositionListenerActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/PositionListenerActivity.java
index 65d7363..6b6287d 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/PositionListenerActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/PositionListenerActivity.java
@@ -75,11 +75,11 @@
                 // Although we could do this in a single call, the real one won't be - so mimic that
                 if (dir.x != 0f) {
                     node.stretch(0f, 0f, (float) getWidth(), (float) getHeight(),
-                            dir.x, 0f, maxStretchAmount);
+                            dir.x, 0f, maxStretchAmount, maxStretchAmount);
                 }
                 if (dir.y != 0f) {
                     node.stretch(0f, 0f, (float) getWidth(), (float) getHeight(),
-                            0f, dir.y, maxStretchAmount);
+                            0f, dir.y, maxStretchAmount, maxStretchAmount);
                 }
             }
         };
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java
index 9bd933a..912aee6 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java
@@ -415,6 +415,7 @@
                         bounds.height(),
                         mOverScrollX,
                         mOverScrollY,
+                        mStretchDistance,
                         mStretchDistance
                 );
             }
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/StretchySurfaceViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/StretchySurfaceViewActivity.java
index d604244..67b9be5 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/StretchySurfaceViewActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/StretchySurfaceViewActivity.java
@@ -99,7 +99,8 @@
                 super.onDraw(canvas);
 
                 RenderNode node = ((RecordingCanvas) canvas).mNode;
-                node.stretch(0f, 0f, getWidth(), getHeight() / 2f, 0f, 1f, 400f);
+                node.stretch(0f, 0f, getWidth(), getHeight() / 2f, 0f,
+                        1f, 400f, 400f);
             }
         };
 
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index 0dfec75..a7ad695 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -69,6 +69,7 @@
 import android.os.Build;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.ArraySet;
+import android.util.Range;
 
 import androidx.test.runner.AndroidJUnit4;
 
@@ -240,72 +241,93 @@
     @Test
     public void testSetUids() {
         final NetworkCapabilities netCap = new NetworkCapabilities();
-        final Set<UidRange> uids = new ArraySet<>();
-        uids.add(new UidRange(50, 100));
-        uids.add(new UidRange(3000, 4000));
-        netCap.setUids(uids);
-        assertTrue(netCap.appliesToUid(50));
-        assertTrue(netCap.appliesToUid(80));
-        assertTrue(netCap.appliesToUid(100));
+        // Null uids match all UIDs
+        netCap.setUids(null);
+        assertTrue(netCap.appliesToUid(10));
+        assertTrue(netCap.appliesToUid(200));
         assertTrue(netCap.appliesToUid(3000));
-        assertTrue(netCap.appliesToUid(3001));
-        assertFalse(netCap.appliesToUid(10));
-        assertFalse(netCap.appliesToUid(25));
-        assertFalse(netCap.appliesToUid(49));
-        assertFalse(netCap.appliesToUid(101));
-        assertFalse(netCap.appliesToUid(2000));
-        assertFalse(netCap.appliesToUid(100000));
-
+        assertTrue(netCap.appliesToUid(10010));
         assertTrue(netCap.appliesToUidRange(new UidRange(50, 100)));
         assertTrue(netCap.appliesToUidRange(new UidRange(70, 72)));
         assertTrue(netCap.appliesToUidRange(new UidRange(3500, 3912)));
-        assertFalse(netCap.appliesToUidRange(new UidRange(1, 100)));
-        assertFalse(netCap.appliesToUidRange(new UidRange(49, 100)));
-        assertFalse(netCap.appliesToUidRange(new UidRange(1, 10)));
-        assertFalse(netCap.appliesToUidRange(new UidRange(60, 101)));
-        assertFalse(netCap.appliesToUidRange(new UidRange(60, 3400)));
-
-        NetworkCapabilities netCap2 = new NetworkCapabilities();
-        // A new netcap object has null UIDs, so anything will satisfy it.
-        assertTrue(netCap2.satisfiedByUids(netCap));
-        // Still not equal though.
-        assertFalse(netCap2.equalsUids(netCap));
-        netCap2.setUids(uids);
-        assertTrue(netCap2.satisfiedByUids(netCap));
-        assertTrue(netCap.equalsUids(netCap2));
-        assertTrue(netCap2.equalsUids(netCap));
-
-        uids.add(new UidRange(600, 700));
-        netCap2.setUids(uids);
-        assertFalse(netCap2.satisfiedByUids(netCap));
-        assertFalse(netCap.appliesToUid(650));
-        assertTrue(netCap2.appliesToUid(650));
-        netCap.combineCapabilities(netCap2);
-        assertTrue(netCap2.satisfiedByUids(netCap));
-        assertTrue(netCap.appliesToUid(650));
-        assertFalse(netCap.appliesToUid(500));
-
-        assertTrue(new NetworkCapabilities().satisfiedByUids(netCap));
-        netCap.combineCapabilities(new NetworkCapabilities());
-        assertTrue(netCap.appliesToUid(500));
         assertTrue(netCap.appliesToUidRange(new UidRange(1, 100000)));
-        assertFalse(netCap2.appliesToUid(500));
-        assertFalse(netCap2.appliesToUidRange(new UidRange(1, 100000)));
-        assertTrue(new NetworkCapabilities().satisfiedByUids(netCap));
+
+        if (isAtLeastS()) {
+            final Set<Range<Integer>> uids = new ArraySet<>();
+            uids.add(uidRange(50, 100));
+            uids.add(uidRange(3000, 4000));
+            netCap.setUids(uids);
+            assertTrue(netCap.appliesToUid(50));
+            assertTrue(netCap.appliesToUid(80));
+            assertTrue(netCap.appliesToUid(100));
+            assertTrue(netCap.appliesToUid(3000));
+            assertTrue(netCap.appliesToUid(3001));
+            assertFalse(netCap.appliesToUid(10));
+            assertFalse(netCap.appliesToUid(25));
+            assertFalse(netCap.appliesToUid(49));
+            assertFalse(netCap.appliesToUid(101));
+            assertFalse(netCap.appliesToUid(2000));
+            assertFalse(netCap.appliesToUid(100000));
+
+            assertTrue(netCap.appliesToUidRange(new UidRange(50, 100)));
+            assertTrue(netCap.appliesToUidRange(new UidRange(70, 72)));
+            assertTrue(netCap.appliesToUidRange(new UidRange(3500, 3912)));
+            assertFalse(netCap.appliesToUidRange(new UidRange(1, 100)));
+            assertFalse(netCap.appliesToUidRange(new UidRange(49, 100)));
+            assertFalse(netCap.appliesToUidRange(new UidRange(1, 10)));
+            assertFalse(netCap.appliesToUidRange(new UidRange(60, 101)));
+            assertFalse(netCap.appliesToUidRange(new UidRange(60, 3400)));
+
+            NetworkCapabilities netCap2 = new NetworkCapabilities();
+            // A new netcap object has null UIDs, so anything will satisfy it.
+            assertTrue(netCap2.satisfiedByUids(netCap));
+            // Still not equal though.
+            assertFalse(netCap2.equalsUids(netCap));
+            netCap2.setUids(uids);
+            assertTrue(netCap2.satisfiedByUids(netCap));
+            assertTrue(netCap.equalsUids(netCap2));
+            assertTrue(netCap2.equalsUids(netCap));
+
+            uids.add(uidRange(600, 700));
+            netCap2.setUids(uids);
+            assertFalse(netCap2.satisfiedByUids(netCap));
+            assertFalse(netCap.appliesToUid(650));
+            assertTrue(netCap2.appliesToUid(650));
+            netCap.combineCapabilities(netCap2);
+            assertTrue(netCap2.satisfiedByUids(netCap));
+            assertTrue(netCap.appliesToUid(650));
+            assertFalse(netCap.appliesToUid(500));
+
+            assertTrue(new NetworkCapabilities().satisfiedByUids(netCap));
+            netCap.combineCapabilities(new NetworkCapabilities());
+            assertTrue(netCap.appliesToUid(500));
+            assertTrue(netCap.appliesToUidRange(new UidRange(1, 100000)));
+            assertFalse(netCap2.appliesToUid(500));
+            assertFalse(netCap2.appliesToUidRange(new UidRange(1, 100000)));
+            assertTrue(new NetworkCapabilities().satisfiedByUids(netCap));
+
+            // Null uids satisfies everything.
+            netCap.setUids(null);
+            assertTrue(netCap2.satisfiedByUids(netCap));
+            assertTrue(netCap.satisfiedByUids(netCap2));
+            netCap2.setUids(null);
+            assertTrue(netCap2.satisfiedByUids(netCap));
+            assertTrue(netCap.satisfiedByUids(netCap2));
+        }
     }
 
     @Test
     public void testParcelNetworkCapabilities() {
-        final Set<UidRange> uids = new ArraySet<>();
-        uids.add(new UidRange(50, 100));
-        uids.add(new UidRange(3000, 4000));
+        final Set<Range<Integer>> uids = new ArraySet<>();
+        uids.add(uidRange(50, 100));
+        uids.add(uidRange(3000, 4000));
         final NetworkCapabilities netCap = new NetworkCapabilities()
             .addCapability(NET_CAPABILITY_INTERNET)
-            .setUids(uids)
             .addCapability(NET_CAPABILITY_EIMS)
             .addCapability(NET_CAPABILITY_NOT_METERED);
         if (isAtLeastS()) {
             netCap.setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2));
+            netCap.setUids(uids);
         } else if (isAtLeastR()) {
             netCap.setOwnerUid(123);
             netCap.setAdministratorUids(new int[] {5, 11});
@@ -540,12 +562,16 @@
         assertFalse(nc1.satisfiedByNetworkCapabilities(nc2));
     }
 
-    private ArraySet<UidRange> uidRange(int from, int to) {
-        final ArraySet<UidRange> range = new ArraySet<>(1);
-        range.add(new UidRange(from, to));
+    private ArraySet<Range<Integer>> uidRanges(int from, int to) {
+        final ArraySet<Range<Integer>> range = new ArraySet<>(1);
+        range.add(uidRange(from, to));
         return range;
     }
 
+    private Range<Integer> uidRange(int from, int to) {
+        return new Range<Integer>(from, to);
+    }
+
     @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
     public void testSetAdministratorUids() {
         NetworkCapabilities nc =
@@ -601,23 +627,23 @@
         } catch (IllegalStateException expected) {}
         nc1.setSSID(TEST_SSID);
 
-        nc1.setUids(uidRange(10, 13));
-        assertNotEquals(nc1, nc2);
-        nc2.combineCapabilities(nc1);  // Everything + 10~13 is still everything.
-        assertNotEquals(nc1, nc2);
-        nc1.combineCapabilities(nc2);  // 10~13 + everything is everything.
-        assertEquals(nc1, nc2);
-        nc1.setUids(uidRange(10, 13));
-        nc2.setUids(uidRange(20, 23));
-        assertNotEquals(nc1, nc2);
-        nc1.combineCapabilities(nc2);
-        assertTrue(nc1.appliesToUid(12));
-        assertFalse(nc2.appliesToUid(12));
-        assertTrue(nc1.appliesToUid(22));
-        assertTrue(nc2.appliesToUid(22));
-
-        // Verify the subscription id list can be combined only when they are equal.
         if (isAtLeastS()) {
+            nc1.setUids(uidRanges(10, 13));
+            assertNotEquals(nc1, nc2);
+            nc2.combineCapabilities(nc1);  // Everything + 10~13 is still everything.
+            assertNotEquals(nc1, nc2);
+            nc1.combineCapabilities(nc2);  // 10~13 + everything is everything.
+            assertEquals(nc1, nc2);
+            nc1.setUids(uidRanges(10, 13));
+            nc2.setUids(uidRanges(20, 23));
+            assertNotEquals(nc1, nc2);
+            nc1.combineCapabilities(nc2);
+            assertTrue(nc1.appliesToUid(12));
+            assertFalse(nc2.appliesToUid(12));
+            assertTrue(nc1.appliesToUid(22));
+            assertTrue(nc2.appliesToUid(22));
+
+            // Verify the subscription id list can be combined only when they are equal.
             nc1.setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2));
             nc2.setSubIds(Set.of(TEST_SUBID2));
             assertThrows(IllegalStateException.class, () -> nc2.combineCapabilities(nc1));
@@ -773,8 +799,11 @@
         if (isAtLeastR()) {
             assertTrue(DIFFERENT_TEST_SSID.equals(nc2.getSsid()));
         }
-
-        nc1.setUids(uidRange(10, 13));
+        if (isAtLeastS()) {
+            nc1.setUids(uidRanges(10, 13));
+        } else {
+            nc1.setUids(null);
+        }
         nc2.set(nc1);  // Overwrites, as opposed to combineCapabilities
         assertEquals(nc1, nc2);
 
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 2a2dc56..db49e0b 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
@@ -44,12 +44,10 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.server.ConnectivityService
-import com.android.server.LocalServices
 import com.android.server.NetworkAgentWrapper
 import com.android.server.TestNetIdManager
 import com.android.server.connectivity.MockableSystemProperties
 import com.android.server.connectivity.ProxyTracker
-import com.android.server.net.NetworkPolicyManagerInternal
 import com.android.testutils.TestableNetworkCallback
 import org.junit.After
 import org.junit.Before
@@ -162,10 +160,6 @@
         networkStackClient.init()
         networkStackClient.start()
 
-        LocalServices.removeServiceForTest(NetworkPolicyManagerInternal::class.java)
-        LocalServices.addService(NetworkPolicyManagerInternal::class.java,
-                mock(NetworkPolicyManagerInternal::class.java))
-
         service = TestConnectivityService(makeDependencies())
         cm = ConnectivityManager(context, service)
         context.addMockSystemService(Context.CONNECTIVITY_SERVICE, cm)
diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
index 01d8186..e2d43cb 100644
--- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
+++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -44,11 +44,11 @@
 import android.net.NetworkSpecifier;
 import android.net.QosFilter;
 import android.net.SocketKeepalive;
-import android.net.UidRange;
 import android.os.ConditionVariable;
 import android.os.HandlerThread;
 import android.os.Message;
 import android.util.Log;
+import android.util.Range;
 
 import com.android.net.module.util.ArrayTrackRecord;
 import com.android.server.connectivity.ConnectivityConstants;
@@ -222,7 +222,7 @@
         mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
     }
 
-    public void setUids(Set<UidRange> uids) {
+    public void setUids(Set<Range<Integer>> uids) {
         mNetworkCapabilities.setUids(uids);
         mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
     }
diff --git a/tests/net/java/android/net/VpnTransportInfoTest.java b/tests/net/java/android/net/VpnTransportInfoTest.java
index d04c87b..b7a42ec 100644
--- a/tests/net/java/android/net/VpnTransportInfoTest.java
+++ b/tests/net/java/android/net/VpnTransportInfoTest.java
@@ -42,7 +42,13 @@
         VpnTransportInfo v1 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM);
         VpnTransportInfo v2 = new VpnTransportInfo(VpnManager.TYPE_VPN_SERVICE);
         VpnTransportInfo v3 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM);
+        VpnTransportInfo v4 = new VpnTransportInfo(VpnManager.TYPE_VPN_LEGACY);
+        VpnTransportInfo v5 = new VpnTransportInfo(VpnManager.TYPE_VPN_OEM);
+
         assertNotEquals(v1, v2);
+        assertNotEquals(v3, v4);
+        assertNotEquals(v4, v5);
+
         assertEquals(v1, v3);
         assertEquals(v1.hashCode(), v3.hashCode());
     }
diff --git a/tests/net/java/android/net/util/KeepaliveUtilsTest.kt b/tests/net/java/android/net/util/KeepaliveUtilsTest.kt
index 8ea226d..b62bdbc 100644
--- a/tests/net/java/android/net/util/KeepaliveUtilsTest.kt
+++ b/tests/net/java/android/net/util/KeepaliveUtilsTest.kt
@@ -18,6 +18,7 @@
 
 import android.content.Context
 import android.content.res.Resources
+import android.net.ConnectivityResources
 import android.net.NetworkCapabilities
 import android.net.NetworkCapabilities.MAX_TRANSPORT
 import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
@@ -26,13 +27,15 @@
 import android.net.NetworkCapabilities.TRANSPORT_WIFI
 import androidx.test.filters.SmallTest
 import com.android.internal.R
+import org.junit.After
 import org.junit.Assert.assertArrayEquals
 import org.junit.Assert.assertEquals
 import org.junit.Assert.fail
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
-import org.mockito.ArgumentMatchers
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mockito.any
 import org.mockito.Mockito.doReturn
 import org.mockito.Mockito.mock
 
@@ -47,21 +50,33 @@
 class KeepaliveUtilsTest {
 
     // Prepare mocked context with given resource strings.
-    private fun getMockedContextWithStringArrayRes(id: Int, res: Array<out String?>?): Context {
+    private fun getMockedContextWithStringArrayRes(
+        id: Int,
+        name: String,
+        res: Array<out String?>?
+    ): Context {
         val mockRes = mock(Resources::class.java)
-        doReturn(res).`when`(mockRes).getStringArray(ArgumentMatchers.eq(id))
+        doReturn(res).`when`(mockRes).getStringArray(eq(id))
+        doReturn(id).`when`(mockRes).getIdentifier(eq(name), any(), any())
 
         return mock(Context::class.java).apply {
             doReturn(mockRes).`when`(this).getResources()
+            ConnectivityResources.setResourcesContextForTest(this)
         }
     }
 
+    @After
+    fun tearDown() {
+        ConnectivityResources.setResourcesContextForTest(null)
+    }
+
     @Test
     fun testGetSupportedKeepalives() {
         fun assertRunWithException(res: Array<out String?>?) {
             try {
                 val mockContext = getMockedContextWithStringArrayRes(
-                        R.array.config_networkSupportedKeepaliveCount, res)
+                        R.array.config_networkSupportedKeepaliveCount,
+                        "config_networkSupportedKeepaliveCount", res)
                 KeepaliveUtils.getSupportedKeepalives(mockContext)
                 fail("Expected KeepaliveDeviceConfigurationException")
             } catch (expected: KeepaliveUtils.KeepaliveDeviceConfigurationException) {
@@ -89,7 +104,8 @@
         val expectedValidRes = intArrayOf(3, 0, 0, 0, 4, 0, 0, 0)
 
         val mockContext = getMockedContextWithStringArrayRes(
-                R.array.config_networkSupportedKeepaliveCount, validRes)
+                R.array.config_networkSupportedKeepaliveCount,
+                "config_networkSupportedKeepaliveCount", validRes)
         val actual = KeepaliveUtils.getSupportedKeepalives(mockContext)
         assertArrayEquals(expectedValidRes, actual)
     }
diff --git a/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt b/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt
index c1315f6..25aa626 100644
--- a/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt
+++ b/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt
@@ -21,18 +21,20 @@
 import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER
 import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE
 import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY
+import android.net.ConnectivityResources
+import android.net.ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI
+import android.net.ConnectivitySettingsManager.NETWORK_METERED_MULTIPATH_PREFERENCE
 import android.net.util.MultinetworkPolicyTracker.ActiveDataSubscriptionIdListener
 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.connectivity.resources.R
 import com.android.internal.util.test.FakeSettingsProvider
+import org.junit.After
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertTrue
@@ -41,6 +43,7 @@
 import org.mockito.ArgumentCaptor
 import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.ArgumentMatchers.argThat
+import org.mockito.ArgumentMatchers.eq
 import org.mockito.Mockito.any
 import org.mockito.Mockito.doReturn
 import org.mockito.Mockito.mock
@@ -57,6 +60,8 @@
 @SmallTest
 class MultinetworkPolicyTrackerTest {
     private val resources = mock(Resources::class.java).also {
+        doReturn(R.integer.config_networkAvoidBadWifi).`when`(it).getIdentifier(
+                eq("config_networkAvoidBadWifi"), eq("integer"), any())
         doReturn(0).`when`(it).getInteger(R.integer.config_networkAvoidBadWifi)
     }
     private val telephonyManager = mock(TelephonyManager::class.java)
@@ -75,6 +80,7 @@
         doReturn(resources).`when`(it).resources
         doReturn(it).`when`(it).createConfigurationContext(any())
         Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "1")
+        ConnectivityResources.setResourcesContextForTest(it)
     }
     private val tracker = MultinetworkPolicyTracker(context, null /* handler */)
 
@@ -85,6 +91,11 @@
         assertEquals(preference, tracker.meteredMultipathPreference)
     }
 
+    @After
+    fun tearDown() {
+        ConnectivityResources.setResourcesContextForTest(null)
+    }
+
     @Test
     fun testUpdateMeteredMultipathPreference() {
         assertMultipathPreference(MULTIPATH_PREFERENCE_HANDOVER)
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index a0b13c8..0b31999 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -87,10 +87,10 @@
 import static android.net.NetworkCapabilities.TRANSPORT_VPN;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
-import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED;
-import static android.net.NetworkPolicyManager.RULE_NONE;
-import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
-import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
+import static android.net.NetworkPolicyManager.BLOCKED_METERED_REASON_DATA_SAVER;
+import static android.net.NetworkPolicyManager.BLOCKED_METERED_REASON_USER_RESTRICTED;
+import static android.net.NetworkPolicyManager.BLOCKED_REASON_BATTERY_SAVER;
+import static android.net.NetworkPolicyManager.BLOCKED_REASON_NONE;
 import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID;
 import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK;
 import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
@@ -179,6 +179,8 @@
 import android.net.ConnectivityManager.PacketKeepalive;
 import android.net.ConnectivityManager.PacketKeepaliveCallback;
 import android.net.ConnectivityManager.TooManyRequestsException;
+import android.net.ConnectivityResources;
+import android.net.ConnectivitySettingsManager;
 import android.net.ConnectivityThread;
 import android.net.DataStallReportParcelable;
 import android.net.EthernetManager;
@@ -187,7 +189,6 @@
 import android.net.INetd;
 import android.net.INetworkMonitor;
 import android.net.INetworkMonitorCallbacks;
-import android.net.INetworkPolicyListener;
 import android.net.IOnCompleteListener;
 import android.net.IQosCallback;
 import android.net.InetAddresses;
@@ -206,6 +207,7 @@
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkPolicyManager;
+import android.net.NetworkPolicyManager.NetworkPolicyCallback;
 import android.net.NetworkRequest;
 import android.net.NetworkScore;
 import android.net.NetworkSpecifier;
@@ -266,12 +268,14 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.Pair;
+import android.util.Range;
 import android.util.SparseArray;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.connectivity.resources.R;
 import com.android.internal.net.VpnConfig;
 import com.android.internal.net.VpnProfile;
 import com.android.internal.util.ArrayUtils;
@@ -281,7 +285,6 @@
 import com.android.net.module.util.ArrayTrackRecord;
 import com.android.server.ConnectivityService.ConnectivityDiagnosticsCallbackInfo;
 import com.android.server.connectivity.ConnectivityConstants;
-import com.android.server.connectivity.ConnectivityResources;
 import com.android.server.connectivity.MockableSystemProperties;
 import com.android.server.connectivity.Nat464Xlat;
 import com.android.server.connectivity.NetworkAgentInfo;
@@ -291,7 +294,6 @@
 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;
 import com.android.testutils.HandlerUtils;
 import com.android.testutils.RecorderCallback.CallbackEntry;
@@ -422,7 +424,7 @@
     private TestNetworkAgentWrapper mEthernetNetworkAgent;
     private MockVpn mMockVpn;
     private Context mContext;
-    private INetworkPolicyListener mPolicyListener;
+    private NetworkPolicyCallback mPolicyCallback;
     private WrappedMultinetworkPolicyTracker mPolicyTracker;
     private HandlerThread mAlarmManagerThread;
     private TestNetIdManager mNetIdManager;
@@ -434,8 +436,7 @@
     private TestNetworkCallback mProfileDefaultNetworkCallback;
 
     // State variables required to emulate NetworkPolicyManagerService behaviour.
-    private int mUidRules = RULE_NONE;
-    private boolean mRestrictBackground = false;
+    private int mBlockedReasons = BLOCKED_REASON_NONE;
 
     @Mock DeviceIdleInternal mDeviceIdleInternal;
     @Mock INetworkManagementService mNetworkManagementService;
@@ -1158,7 +1159,7 @@
         }
 
         public void setUids(Set<UidRange> uids) {
-            mNetworkCapabilities.setUids(uids);
+            mNetworkCapabilities.setUids(UidRange.toIntRanges(uids));
             if (mAgentRegistered) {
                 mMockNetworkAgent.setNetworkCapabilities(mNetworkCapabilities, true);
             }
@@ -1374,28 +1375,13 @@
     }
 
     private void mockUidNetworkingBlocked() {
-        doAnswer(i -> mContext.getSystemService(NetworkPolicyManager.class)
-                .checkUidNetworkingBlocked(i.getArgument(0) /* uid */, mUidRules,
-                        i.getArgument(1) /* metered */, mRestrictBackground)
+        doAnswer(i -> NetworkPolicyManager.isUidBlocked(mBlockedReasons, i.getArgument(1))
         ).when(mNetworkPolicyManager).isUidNetworkingBlocked(anyInt(), anyBoolean());
-
-        doAnswer(inv -> mContext.getSystemService(NetworkPolicyManager.class)
-                .checkUidNetworkingBlocked(inv.getArgument(0) /* uid */,
-                        inv.getArgument(1) /* uidRules */,
-                        inv.getArgument(2) /* isNetworkMetered */,
-                        inv.getArgument(3) /* isBackgroundRestricted */)
-        ).when(mNetworkPolicyManager).checkUidNetworkingBlocked(
-                anyInt(), anyInt(), anyBoolean(), anyBoolean());
     }
 
-    private void setUidRulesChanged(int uidRules) throws RemoteException {
-        mUidRules = uidRules;
-        mPolicyListener.onUidRulesChanged(Process.myUid(), mUidRules);
-    }
-
-    private void setRestrictBackgroundChanged(boolean restrictBackground) throws RemoteException {
-        mRestrictBackground = restrictBackground;
-        mPolicyListener.onRestrictBackgroundChanged(mRestrictBackground);
+    private void setBlockedReasonChanged(int blockedReasons) {
+        mBlockedReasons = blockedReasons;
+        mPolicyCallback.onUidBlockedReasonChanged(Process.myUid(), blockedReasons);
     }
 
     private Nat464Xlat getNat464Xlat(NetworkAgentWrapper mna) {
@@ -1463,6 +1449,8 @@
     }
 
     private static final int PRIMARY_USER = 0;
+    private static final UidRange PRIMARY_UIDRANGE =
+            UidRange.createForUser(UserHandle.of(PRIMARY_USER));
     private static final int APP1_UID = UserHandle.getUid(PRIMARY_USER, 10100);
     private static final int APP2_UID = UserHandle.getUid(PRIMARY_USER, 10101);
     private static final int VPN_UID = UserHandle.getUid(PRIMARY_USER, 10043);
@@ -1516,9 +1504,6 @@
         mServiceContext = new MockContext(InstrumentationRegistry.getContext(),
                 new FakeSettingsProvider());
         mServiceContext.setUseRegisteredHandlers(true);
-        LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
-        LocalServices.addService(
-                NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class));
 
         mAlarmManagerThread = new HandlerThread("TestAlarmManager");
         mAlarmManagerThread.start();
@@ -1537,10 +1522,11 @@
         mService.mNascentDelayMs = TEST_NASCENT_DELAY_MS;
         verify(mDeps).makeMultinetworkPolicyTracker(any(), any(), any());
 
-        final ArgumentCaptor<INetworkPolicyListener> policyListenerCaptor =
-                ArgumentCaptor.forClass(INetworkPolicyListener.class);
-        verify(mNetworkPolicyManager).registerListener(policyListenerCaptor.capture());
-        mPolicyListener = policyListenerCaptor.getValue();
+        final ArgumentCaptor<NetworkPolicyCallback> policyCallbackCaptor =
+                ArgumentCaptor.forClass(NetworkPolicyCallback.class);
+        verify(mNetworkPolicyManager).registerNetworkPolicyCallback(any(),
+                policyCallbackCaptor.capture());
+        mPolicyCallback = policyCallbackCaptor.getValue();
 
         // Create local CM before sending system ready so that we can answer
         // getSystemService() correctly.
@@ -1553,7 +1539,7 @@
         mQosCallbackTracker = mock(QosCallbackTracker.class);
 
         // Ensure that the default setting for Captive Portals is used for most tests
-        setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
+        setCaptivePortalMode(ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_PROMPT);
         setAlwaysOnNetworks(false);
         setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com");
     }
@@ -1584,11 +1570,27 @@
                 com.android.connectivity.resources.R.string.config_networkCaptivePortalServerUrl);
         doReturn(new String[]{ WIFI_WOL_IFNAME }).when(mResources).getStringArray(
                 com.android.connectivity.resources.R.array.config_wakeonlan_supported_interfaces);
-        final com.android.server.connectivity.ConnectivityResources connRes = mock(
-                ConnectivityResources.class);
+        doReturn(new String[] { "0,1", "1,3" }).when(mResources).getStringArray(
+                com.android.connectivity.resources.R.array.config_networkSupportedKeepaliveCount);
+        doReturn(com.android.connectivity.resources.R.array.config_networkSupportedKeepaliveCount)
+                .when(mResources).getIdentifier(eq("config_networkSupportedKeepaliveCount"),
+                eq("array"), any());
+        doReturn(com.android.connectivity.resources.R.array.network_switch_type_name)
+                .when(mResources).getIdentifier(eq("network_switch_type_name"),
+                eq("array"), any());
+
+        // We don't test the actual notification value strings, so just return an empty array.
+        // It doesn't matter what the values are as long as it's not null.
+        doReturn(new String[0]).when(mResources).getStringArray(R.array.network_switch_type_name);
+
+        final ConnectivityResources connRes = mock(ConnectivityResources.class);
         doReturn(mResources).when(connRes).get();
         doReturn(connRes).when(deps).getResources(any());
 
+        final Context mockResContext = mock(Context.class);
+        doReturn(mResources).when(mockResContext).getResources();
+        ConnectivityResources.setResourcesContextForTest(mockResContext);
+
         return deps;
     }
 
@@ -1644,6 +1646,7 @@
         waitForIdle();
 
         FakeSettingsProvider.clearSettingsProvider();
+        ConnectivityResources.setResourcesContextForTest(null);
 
         mCsHandlerThread.quitSafely();
         mAlarmManagerThread.quitSafely();
@@ -3406,7 +3409,7 @@
                 .addCapability(NET_CAPABILITY_VALIDATED).build();
         mCm.registerNetworkCallback(validatedRequest, validatedCallback);
 
-        setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_AVOID);
+        setCaptivePortalMode(ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_AVOID);
         // Bring up a network with a captive portal.
         // Expect it to fail to connect and not result in any callbacks.
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
@@ -4056,20 +4059,21 @@
 
     private void setCaptivePortalMode(int mode) {
         ContentResolver cr = mServiceContext.getContentResolver();
-        Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE, mode);
+        Settings.Global.putInt(cr, ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE, mode);
     }
 
     private void setAlwaysOnNetworks(boolean enable) {
         ContentResolver cr = mServiceContext.getContentResolver();
-        Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, enable ? 1 : 0);
+        Settings.Global.putInt(cr, ConnectivitySettingsManager.MOBILE_DATA_ALWAYS_ON,
+                enable ? 1 : 0);
         mService.updateAlwaysOnNetworks();
         waitForIdle();
     }
 
     private void setPrivateDnsSettings(String mode, String specifier) {
         final ContentResolver cr = mServiceContext.getContentResolver();
-        Settings.Global.putString(cr, Settings.Global.PRIVATE_DNS_MODE, mode);
-        Settings.Global.putString(cr, Settings.Global.PRIVATE_DNS_SPECIFIER, specifier);
+        Settings.Global.putString(cr, ConnectivitySettingsManager.PRIVATE_DNS_MODE, mode);
+        Settings.Global.putString(cr, ConnectivitySettingsManager.PRIVATE_DNS_SPECIFIER, specifier);
         mService.updatePrivateDnsSettings();
         waitForIdle();
     }
@@ -4307,7 +4311,7 @@
     @Test
     public void testAvoidBadWifiSetting() throws Exception {
         final ContentResolver cr = mServiceContext.getContentResolver();
-        final String settingName = Settings.Global.NETWORK_AVOID_BAD_WIFI;
+        final String settingName = ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI;
 
         mPolicyTracker.mConfigRestrictsAvoidBadWifi = false;
         String[] values = new String[] {null, "0", "1"};
@@ -4341,6 +4345,7 @@
         assertTrue(mPolicyTracker.shouldNotifyWifiUnvalidated());
     }
 
+    @Ignore("Refactoring in progress b/178071397")
     @Test
     public void testAvoidBadWifi() throws Exception {
         final ContentResolver cr = mServiceContext.getContentResolver();
@@ -4364,7 +4369,7 @@
         TestNetworkCallback validatedWifiCallback = new TestNetworkCallback();
         mCm.registerNetworkCallback(validatedWifiRequest, validatedWifiCallback);
 
-        Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 0);
+        Settings.Global.putInt(cr, ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI, 0);
         mPolicyTracker.reevaluate();
 
         // Bring up validated cell.
@@ -4432,7 +4437,7 @@
         validatedWifiCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
 
         // Simulate the user selecting "switch" and checking the don't ask again checkbox.
-        Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
+        Settings.Global.putInt(cr, ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI, 1);
         mPolicyTracker.reevaluate();
 
         // We now switch to cell.
@@ -4445,11 +4450,11 @@
 
         // Simulate the user turning the cellular fallback setting off and then on.
         // We switch to wifi and then to cell.
-        Settings.Global.putString(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, null);
+        Settings.Global.putString(cr, ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI, null);
         mPolicyTracker.reevaluate();
         defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         assertEquals(mCm.getActiveNetwork(), wifiNetwork);
-        Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
+        Settings.Global.putInt(cr, ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI, 1);
         mPolicyTracker.reevaluate();
         defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
         assertEquals(mCm.getActiveNetwork(), cellNetwork);
@@ -4468,7 +4473,7 @@
     @Test
     public void testMeteredMultipathPreferenceSetting() throws Exception {
         final ContentResolver cr = mServiceContext.getContentResolver();
-        final String settingName = Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
+        final String settingName = ConnectivitySettingsManager.NETWORK_METERED_MULTIPATH_PREFERENCE;
 
         for (int config : Arrays.asList(0, 3, 2)) {
             for (String setting: Arrays.asList(null, "0", "2", "1")) {
@@ -6944,7 +6949,7 @@
         final int uid = Process.myUid();
         NetworkCapabilities nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
         assertNotNull("nc=" + nc, nc.getUids());
-        assertEquals(nc.getUids(), uidRangesForUids(uid));
+        assertEquals(nc.getUids(), UidRange.toIntRanges(uidRangesForUids(uid)));
         assertVpnTransportInfo(nc, VpnManager.TYPE_VPN_SERVICE);
 
         // Set an underlying network and expect to see the VPN transports change.
@@ -6969,10 +6974,13 @@
 
         // Expect that the VPN UID ranges contain both |uid| and the UID range for the newly-added
         // restricted user.
+        final UidRange rRange = UidRange.createForUser(UserHandle.of(RESTRICTED_USER));
+        final Range<Integer> restrictUidRange = new Range<Integer>(rRange.start, rRange.stop);
+        final Range<Integer> singleUidRange = new Range<Integer>(uid, uid);
         callback.expectCapabilitiesThat(mMockVpn, (caps)
                 -> caps.getUids().size() == 2
-                && caps.getUids().contains(new UidRange(uid, uid))
-                && caps.getUids().contains(createUidRange(RESTRICTED_USER))
+                && caps.getUids().contains(singleUidRange)
+                && caps.getUids().contains(restrictUidRange)
                 && caps.hasTransport(TRANSPORT_VPN)
                 && caps.hasTransport(TRANSPORT_WIFI));
 
@@ -6981,8 +6989,8 @@
         callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
         callback.expectCapabilitiesThat(mMockVpn, (caps)
                 -> caps.getUids().size() == 2
-                && caps.getUids().contains(new UidRange(uid, uid))
-                && caps.getUids().contains(createUidRange(RESTRICTED_USER))
+                && caps.getUids().contains(singleUidRange)
+                && caps.getUids().contains(restrictUidRange)
                 && caps.hasTransport(TRANSPORT_VPN)
                 && !caps.hasTransport(TRANSPORT_WIFI));
 
@@ -6996,7 +7004,7 @@
         // change made just before that (i.e., loss of TRANSPORT_WIFI) is preserved.
         callback.expectCapabilitiesThat(mMockVpn, (caps)
                 -> caps.getUids().size() == 1
-                && caps.getUids().contains(new UidRange(uid, uid))
+                && caps.getUids().contains(singleUidRange)
                 && caps.hasTransport(TRANSPORT_VPN)
                 && !caps.hasTransport(TRANSPORT_WIFI));
     }
@@ -7263,7 +7271,7 @@
         assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
         assertExtraInfoFromCmPresent(mCellNetworkAgent);
 
-        setUidRulesChanged(RULE_REJECT_ALL);
+        setBlockedReasonChanged(BLOCKED_REASON_BATTERY_SAVER);
         cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
         assertNull(mCm.getActiveNetwork());
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
@@ -7271,17 +7279,17 @@
         assertExtraInfoFromCmBlocked(mCellNetworkAgent);
 
         // ConnectivityService should cache it not to invoke the callback again.
-        setUidRulesChanged(RULE_REJECT_METERED);
+        setBlockedReasonChanged(BLOCKED_METERED_REASON_USER_RESTRICTED);
         cellNetworkCallback.assertNoCallback();
 
-        setUidRulesChanged(RULE_NONE);
+        setBlockedReasonChanged(BLOCKED_REASON_NONE);
         cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
         assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
         assertExtraInfoFromCmPresent(mCellNetworkAgent);
 
-        setUidRulesChanged(RULE_REJECT_METERED);
+        setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
         cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
         assertNull(mCm.getActiveNetwork());
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
@@ -7306,33 +7314,33 @@
         assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
         assertExtraInfoFromCmBlocked(mCellNetworkAgent);
 
-        setUidRulesChanged(RULE_ALLOW_METERED);
+        setBlockedReasonChanged(BLOCKED_REASON_NONE);
         cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
         assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
         assertExtraInfoFromCmPresent(mCellNetworkAgent);
 
-        setUidRulesChanged(RULE_NONE);
+        setBlockedReasonChanged(BLOCKED_REASON_NONE);
         cellNetworkCallback.assertNoCallback();
 
         // Restrict background data. Networking is not blocked because the network is unmetered.
-        setRestrictBackgroundChanged(true);
+        setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
         cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
         assertNull(mCm.getActiveNetwork());
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
         assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
         assertExtraInfoFromCmBlocked(mCellNetworkAgent);
-        setRestrictBackgroundChanged(true);
+        setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
         cellNetworkCallback.assertNoCallback();
 
-        setUidRulesChanged(RULE_ALLOW_METERED);
+        setBlockedReasonChanged(BLOCKED_REASON_NONE);
         cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
         assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
         assertExtraInfoFromCmPresent(mCellNetworkAgent);
 
-        setRestrictBackgroundChanged(false);
+        setBlockedReasonChanged(BLOCKED_REASON_NONE);
         cellNetworkCallback.assertNoCallback();
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
         assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
@@ -7349,9 +7357,9 @@
         mockUidNetworkingBlocked();
 
         // No Networkcallbacks invoked before any network is active.
-        setUidRulesChanged(RULE_REJECT_ALL);
-        setUidRulesChanged(RULE_NONE);
-        setUidRulesChanged(RULE_REJECT_METERED);
+        setBlockedReasonChanged(BLOCKED_REASON_BATTERY_SAVER);
+        setBlockedReasonChanged(BLOCKED_REASON_NONE);
+        setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
         defaultCallback.assertNoCallback();
 
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
@@ -7376,8 +7384,8 @@
         defaultCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
 
         // Verify there's no Networkcallbacks invoked after data saver on/off.
-        setRestrictBackgroundChanged(true);
-        setRestrictBackgroundChanged(false);
+        setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
+        setBlockedReasonChanged(BLOCKED_REASON_NONE);
         defaultCallback.assertNoCallback();
 
         mCellNetworkAgent.disconnect();
@@ -7654,7 +7662,7 @@
         assertNotNull(underlying);
         mMockVpn.setVpnType(VpnManager.TYPE_VPN_LEGACY);
         // The legacy lockdown VPN only supports userId 0.
-        final Set<UidRange> ranges = Collections.singleton(createUidRange(PRIMARY_USER));
+        final Set<UidRange> ranges = Collections.singleton(PRIMARY_UIDRANGE);
         mMockVpn.registerAgent(ranges);
         mMockVpn.setUnderlyingNetworks(new Network[]{underlying});
         mMockVpn.connect(true);
@@ -8616,7 +8624,7 @@
         lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
         // The uid range needs to cover the test app so the network is visible to it.
-        final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER));
+        final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
         mMockVpn.establish(lp, VPN_UID, vpnRange);
         assertVpnUidRangesUpdated(true, vpnRange, VPN_UID);
 
@@ -8644,7 +8652,7 @@
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
         lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
         // The uid range needs to cover the test app so the network is visible to it.
-        final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER));
+        final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
         mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange);
         assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID);
 
@@ -8660,7 +8668,7 @@
         lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"), null, "tun0"));
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
         // The uid range needs to cover the test app so the network is visible to it.
-        final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER));
+        final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
         mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange);
         assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID);
 
@@ -8675,7 +8683,7 @@
         lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
         // The uid range needs to cover the test app so the network is visible to it.
-        final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER));
+        final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
         mMockVpn.establish(lp, VPN_UID, vpnRange);
         assertVpnUidRangesUpdated(true, vpnRange, VPN_UID);
 
@@ -8727,7 +8735,7 @@
         lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
         // The uid range needs to cover the test app so the network is visible to it.
-        final UidRange vpnRange = createUidRange(PRIMARY_USER);
+        final UidRange vpnRange = PRIMARY_UIDRANGE;
         final Set<UidRange> vpnRanges = Collections.singleton(vpnRange);
         mMockVpn.establish(lp, VPN_UID, vpnRanges);
         assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID);
@@ -9008,7 +9016,7 @@
 
     private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
             throws Exception {
-        final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER));
+        final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
         mMockVpn.setVpnType(vpnType);
         mMockVpn.establish(new LinkProperties(), vpnOwnerUid, vpnRange);
         assertVpnUidRangesUpdated(true, vpnRange, vpnOwnerUid);
@@ -9568,7 +9576,7 @@
         lp.setInterfaceName("tun0");
         lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
-        final UidRange vpnRange = createUidRange(PRIMARY_USER);
+        final UidRange vpnRange = PRIMARY_UIDRANGE;
         Set<UidRange> vpnRanges = Collections.singleton(vpnRange);
         mMockVpn.establish(lp, VPN_UID, vpnRanges);
         assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID);
@@ -9766,7 +9774,7 @@
                 .thenReturn(hasFeature);
     }
 
-    private UidRange getNriFirstUidRange(
+    private Range<Integer> getNriFirstUidRange(
             @NonNull final ConnectivityService.NetworkRequestInfo nri) {
         return nri.mRequests.get(0).networkCapabilities.getUids().iterator().next();
     }
@@ -9949,11 +9957,11 @@
                                 pref));
 
         // Sort by uid to access nris by index
-        nris.sort(Comparator.comparingInt(nri -> getNriFirstUidRange(nri).start));
-        assertEquals(TEST_PACKAGE_UID, getNriFirstUidRange(nris.get(0)).start);
-        assertEquals(TEST_PACKAGE_UID, getNriFirstUidRange(nris.get(0)).stop);
-        assertEquals(testPackageNameUid2, getNriFirstUidRange(nris.get(1)).start);
-        assertEquals(testPackageNameUid2, getNriFirstUidRange(nris.get(1)).stop);
+        nris.sort(Comparator.comparingInt(nri -> getNriFirstUidRange(nri).getLower()));
+        assertEquals(TEST_PACKAGE_UID, (int) getNriFirstUidRange(nris.get(0)).getLower());
+        assertEquals(TEST_PACKAGE_UID, (int) getNriFirstUidRange(nris.get(0)).getUpper());
+        assertEquals(testPackageNameUid2, (int) getNriFirstUidRange(nris.get(1)).getLower());
+        assertEquals(testPackageNameUid2, (int) getNriFirstUidRange(nris.get(1)).getUpper());
     }
 
     @Test
@@ -9983,17 +9991,17 @@
         // UIDs for all users and all managed packages should be present.
         // Two users each with two packages.
         final int expectedUidSize = 2;
-        final List<UidRange> uids =
+        final List<Range<Integer>> uids =
                 new ArrayList<>(nris.get(0).mRequests.get(0).networkCapabilities.getUids());
         assertEquals(expectedUidSize, uids.size());
 
         // Sort by uid to access nris by index
-        uids.sort(Comparator.comparingInt(uid -> uid.start));
+        uids.sort(Comparator.comparingInt(uid -> uid.getLower()));
         final int secondUserTestPackageUid = UserHandle.getUid(secondUser, TEST_PACKAGE_UID);
-        assertEquals(TEST_PACKAGE_UID, uids.get(0).start);
-        assertEquals(TEST_PACKAGE_UID, uids.get(0).stop);
-        assertEquals(secondUserTestPackageUid, uids.get(1).start);
-        assertEquals(secondUserTestPackageUid, uids.get(1).stop);
+        assertEquals(TEST_PACKAGE_UID, (int) uids.get(0).getLower());
+        assertEquals(TEST_PACKAGE_UID, (int) uids.get(0).getUpper());
+        assertEquals(secondUserTestPackageUid, (int) uids.get(1).getLower());
+        assertEquals(secondUserTestPackageUid, (int) uids.get(1).getUpper());
     }
 
     @Test
@@ -11400,7 +11408,6 @@
         mSystemDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
         mDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
         mProfileDefaultNetworkCallback.assertNoCallback();
-        waitForIdle();
         inOrder.verify(mMockNetd).networkDestroy(mCellNetworkAgent.getNetwork().netId);
 
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
@@ -11419,7 +11426,6 @@
         assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
         inOrder.verify(mMockNetd).networkAddUidRanges(mCellNetworkAgent.getNetwork().netId,
                 uidRangeFor(testHandle));
-        waitForIdle();
         inOrder.verify(mMockNetd).networkDestroy(workAgent.getNetwork().netId);
 
         mCellNetworkAgent.disconnect();
@@ -11427,6 +11433,8 @@
         mDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
         mProfileDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
 
+        // Waiting for the handler to be idle before checking for networkDestroy is necessary
+        // here because ConnectivityService calls onLost before the network is fully torn down.
         waitForIdle();
         inOrder.verify(mMockNetd).networkDestroy(mCellNetworkAgent.getNetwork().netId);
 
@@ -11456,7 +11464,6 @@
         workAgent2.disconnect();
         mProfileDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, workAgent2);
         assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
-        waitForIdle();
         inOrder.verify(mMockNetd).networkDestroy(workAgent2.getNetwork().netId);
 
         assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
index b7ece8f..692c50f 100644
--- a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
@@ -18,15 +18,15 @@
 
 import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
 import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_DEFAULT_MODE;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_SPECIFIER;
 import static android.net.NetworkCapabilities.MAX_TRANSPORT;
 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;
 
 import static com.android.testutils.MiscAsserts.assertContainsExactly;
 import static com.android.testutils.MiscAsserts.assertContainsStringsExactly;
diff --git a/tests/net/java/com/android/server/connectivity/FullScoreTest.kt b/tests/net/java/com/android/server/connectivity/FullScoreTest.kt
new file mode 100644
index 0000000..eb3b4df
--- /dev/null
+++ b/tests/net/java/com/android/server/connectivity/FullScoreTest.kt
@@ -0,0 +1,134 @@
+/*
+ * 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.net.NetworkAgentConfig
+import android.net.NetworkCapabilities
+import android.text.TextUtils
+import android.util.ArraySet
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.server.connectivity.FullScore.MAX_CS_MANAGED_POLICY
+import com.android.server.connectivity.FullScore.POLICY_ACCEPT_UNVALIDATED
+import com.android.server.connectivity.FullScore.POLICY_EVER_USER_SELECTED
+import com.android.server.connectivity.FullScore.POLICY_IS_VALIDATED
+import com.android.server.connectivity.FullScore.POLICY_IS_VPN
+import org.junit.Test
+import org.junit.runner.RunWith
+import kotlin.collections.minOfOrNull
+import kotlin.collections.maxOfOrNull
+import kotlin.reflect.full.staticProperties
+import kotlin.test.assertEquals
+import kotlin.test.assertFailsWith
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class FullScoreTest {
+    // Convenience methods
+    fun FullScore.withPolicies(
+        validated: Boolean = false,
+        vpn: Boolean = false,
+        onceChosen: Boolean = false,
+        acceptUnvalidated: Boolean = false
+    ): FullScore {
+        val nac = NetworkAgentConfig.Builder().apply {
+            setUnvalidatedConnectivityAcceptable(acceptUnvalidated)
+            setExplicitlySelected(onceChosen)
+        }.build()
+        val nc = NetworkCapabilities.Builder().apply {
+            if (vpn) addTransportType(NetworkCapabilities.TRANSPORT_VPN)
+            if (validated) addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
+        }.build()
+        return mixInScore(nc, nac)
+    }
+
+    @Test
+    fun testGetLegacyInt() {
+        val ns = FullScore(50, 0L /* policy */)
+        assertEquals(10, ns.legacyInt) // -40 penalty for not being validated
+        assertEquals(50, ns.legacyIntAsValidated)
+
+        val vpnNs = FullScore(101, 0L /* policy */).withPolicies(vpn = true)
+        assertEquals(101, vpnNs.legacyInt) // VPNs are not subject to unvalidation penalty
+        assertEquals(101, vpnNs.legacyIntAsValidated)
+        assertEquals(101, vpnNs.withPolicies(validated = true).legacyInt)
+        assertEquals(101, vpnNs.withPolicies(validated = true).legacyIntAsValidated)
+
+        val validatedNs = ns.withPolicies(validated = true)
+        assertEquals(50, validatedNs.legacyInt) // No penalty, this is validated
+        assertEquals(50, validatedNs.legacyIntAsValidated)
+
+        val chosenNs = ns.withPolicies(onceChosen = true)
+        assertEquals(10, chosenNs.legacyInt)
+        assertEquals(100, chosenNs.legacyIntAsValidated)
+        assertEquals(10, chosenNs.withPolicies(acceptUnvalidated = true).legacyInt)
+        assertEquals(50, chosenNs.withPolicies(acceptUnvalidated = true).legacyIntAsValidated)
+    }
+
+    @Test
+    fun testToString() {
+        val string = FullScore(10, 0L /* policy */)
+                .withPolicies(vpn = true, acceptUnvalidated = true).toString()
+        assertTrue(string.contains("Score(10"), string)
+        assertTrue(string.contains("ACCEPT_UNVALIDATED"), string)
+        assertTrue(string.contains("IS_VPN"), string)
+        assertFalse(string.contains("IS_VALIDATED"), string)
+        val foundNames = ArraySet<String>()
+        getAllPolicies().forEach {
+            val name = FullScore.policyNameOf(it.get() as Int)
+            assertFalse(TextUtils.isEmpty(name))
+            assertFalse(foundNames.contains(name))
+            foundNames.add(name)
+        }
+        assertFailsWith<IllegalArgumentException> {
+            FullScore.policyNameOf(MAX_CS_MANAGED_POLICY + 1)
+        }
+    }
+
+    fun getAllPolicies() = Regex("POLICY_.*").let { nameRegex ->
+        FullScore::class.staticProperties.filter { it.name.matches(nameRegex) }
+    }
+
+    @Test
+    fun testHasPolicy() {
+        val ns = FullScore(50, 0L /* policy */)
+        assertFalse(ns.hasPolicy(POLICY_IS_VALIDATED))
+        assertFalse(ns.hasPolicy(POLICY_IS_VPN))
+        assertFalse(ns.hasPolicy(POLICY_EVER_USER_SELECTED))
+        assertFalse(ns.hasPolicy(POLICY_ACCEPT_UNVALIDATED))
+        assertTrue(ns.withPolicies(validated = true).hasPolicy(POLICY_IS_VALIDATED))
+        assertTrue(ns.withPolicies(vpn = true).hasPolicy(POLICY_IS_VPN))
+        assertTrue(ns.withPolicies(onceChosen = true).hasPolicy(POLICY_EVER_USER_SELECTED))
+        assertTrue(ns.withPolicies(acceptUnvalidated = true).hasPolicy(POLICY_ACCEPT_UNVALIDATED))
+    }
+
+    @Test
+    fun testMinMaxPolicyConstants() {
+        val policies = getAllPolicies()
+
+        policies.forEach { policy ->
+            assertTrue(policy.get() as Int >= FullScore.MIN_CS_MANAGED_POLICY)
+            assertTrue(policy.get() as Int <= FullScore.MAX_CS_MANAGED_POLICY)
+        }
+        assertEquals(FullScore.MIN_CS_MANAGED_POLICY,
+                policies.minOfOrNull { it.get() as Int })
+        assertEquals(FullScore.MAX_CS_MANAGED_POLICY,
+                policies.maxOfOrNull { it.get() as Int })
+    }
+}
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index ea2b362..9ab60a4 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -357,7 +357,7 @@
         caps.addTransportType(transport);
         NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info,
                 new LinkProperties(), caps, new NetworkScore.Builder().setLegacyInt(50).build(),
-                mCtx, null, new NetworkAgentConfig() /* config */, mConnService, mNetd,
+                mCtx, null, new NetworkAgentConfig.Builder().build(), mConnService, mNetd,
                 mDnsResolver, NetworkProvider.ID_NONE, Binder.getCallingUid(),
                 mQosCallbackTracker, new ConnectivityService.Dependencies());
         nai.everValidated = true;
diff --git a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
index d01dc03..dde77b0 100644
--- a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
@@ -36,6 +36,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
+import android.net.ConnectivityResources;
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
 import android.os.UserHandle;
@@ -45,9 +46,10 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.internal.R;
+import com.android.connectivity.resources.R;
 import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
 
+import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -134,12 +136,26 @@
         when(mCtx.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
                 .thenReturn(mNotificationManager);
         when(mNetworkInfo.getExtraInfo()).thenReturn(TEST_EXTRA_INFO);
+        ConnectivityResources.setResourcesContextForTest(mCtx);
         when(mResources.getColor(anyInt(), any())).thenReturn(0xFF607D8B);
         when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics);
 
+        // Come up with some credible-looking transport names. The actual values do not matter.
+        String[] transportNames = new String[NetworkCapabilities.MAX_TRANSPORT + 1];
+        for (int transport = 0; transport <= NetworkCapabilities.MAX_TRANSPORT; transport++) {
+            transportNames[transport] = NetworkCapabilities.transportNameOf(transport);
+        }
+        when(mResources.getStringArray(R.array.network_switch_type_name))
+            .thenReturn(transportNames);
+
         mManager = new NetworkNotificationManager(mCtx, mTelephonyManager);
     }
 
+    @After
+    public void tearDown() {
+        ConnectivityResources.setResourcesContextForTest(null);
+    }
+
     private void verifyTitleByNetwork(final int id, final NetworkAgentInfo nai, final int title) {
         final String tag = NetworkNotificationManager.tagFor(id);
         mManager.showNotification(id, PRIVATE_DNS_BROKEN, nai, null, null, true);
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 11fcea6..6ad4900 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -23,6 +23,7 @@
 import static android.net.ConnectivityManager.NetworkCallback;
 import static android.net.INetd.IF_STATE_DOWN;
 import static android.net.INetd.IF_STATE_UP;
+import static android.os.UserHandle.PER_USER_RANGE;
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
@@ -74,7 +75,6 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo.DetailedState;
 import android.net.RouteInfo;
-import android.net.UidRange;
 import android.net.UidRangeParcel;
 import android.net.VpnManager;
 import android.net.VpnService;
@@ -181,8 +181,7 @@
             mPackages.put(PKGS[i], PKG_UIDS[i]);
         }
     }
-    private static final UidRange PRI_USER_RANGE =
-            UidRange.createForUser(UserHandle.of(primaryUser.id));
+    private static final Range<Integer> PRI_USER_RANGE = uidRangeForUser(primaryUser.id);
 
     @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext;
     @Mock private UserManager mUserManager;
@@ -260,6 +259,21 @@
                 .thenReturn(tunnelResp);
     }
 
+    private Set<Range<Integer>> rangeSet(Range<Integer> ... ranges) {
+        final Set<Range<Integer>> range = new ArraySet<>();
+        for (Range<Integer> r : ranges) range.add(r);
+
+        return range;
+    }
+
+    private static Range<Integer> uidRangeForUser(int userId) {
+        return new Range<Integer>(userId * PER_USER_RANGE, (userId + 1) * PER_USER_RANGE - 1);
+    }
+
+    private Range<Integer> uidRange(int start, int stop) {
+        return new Range<Integer>(start, stop);
+    }
+
     @Test
     public void testRestrictedProfilesAreAddedToVpn() {
         setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB);
@@ -268,12 +282,10 @@
 
         // Assume the user can have restricted profiles.
         doReturn(true).when(mUserManager).canHaveRestrictedProfile();
-        final Set<UidRange> ranges =
+        final Set<Range<Integer>> ranges =
                 vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, null, null);
 
-        assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
-                PRI_USER_RANGE, UidRange.createForUser(UserHandle.of(restrictedProfileA.id))
-        })), ranges);
+        assertEquals(rangeSet(PRI_USER_RANGE, uidRangeForUser(restrictedProfileA.id)), ranges);
     }
 
     @Test
@@ -281,10 +293,10 @@
         setMockedUsers(primaryUser, managedProfileA);
 
         final Vpn vpn = createVpn(primaryUser.id);
-        final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
+        final Set<Range<Integer>> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
                 null, null);
 
-        assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { PRI_USER_RANGE })), ranges);
+        assertEquals(rangeSet(PRI_USER_RANGE), ranges);
     }
 
     @Test
@@ -292,35 +304,38 @@
         setMockedUsers(primaryUser, restrictedProfileA, managedProfileA);
 
         final Vpn vpn = createVpn(primaryUser.id);
-        final Set<UidRange> ranges = new ArraySet<>();
+        final Set<Range<Integer>> ranges = new ArraySet<>();
         vpn.addUserToRanges(ranges, primaryUser.id, null, null);
 
-        assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { PRI_USER_RANGE })), ranges);
+        assertEquals(rangeSet(PRI_USER_RANGE), ranges);
     }
 
     @Test
     public void testUidAllowAndDenylist() throws Exception {
         final Vpn vpn = createVpn(primaryUser.id);
-        final UidRange user = PRI_USER_RANGE;
+        final Range<Integer> user = PRI_USER_RANGE;
+        final int userStart = user.getLower();
+        final int userStop = user.getUpper();
         final String[] packages = {PKGS[0], PKGS[1], PKGS[2]};
 
         // Allowed list
-        final Set<UidRange> allow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
-                Arrays.asList(packages), null);
-        assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
-            new UidRange(user.start + PKG_UIDS[0], user.start + PKG_UIDS[0]),
-            new UidRange(user.start + PKG_UIDS[1], user.start + PKG_UIDS[2])
-        })), allow);
+        final Set<Range<Integer>> allow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
+                Arrays.asList(packages), null /* disallowedApplications */);
+        assertEquals(rangeSet(
+                uidRange(userStart + PKG_UIDS[0], userStart + PKG_UIDS[0]),
+                uidRange(userStart + PKG_UIDS[1], userStart + PKG_UIDS[2])),
+                allow);
 
         // Denied list
-        final Set<UidRange> disallow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
-                null, Arrays.asList(packages));
-        assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
-            new UidRange(user.start, user.start + PKG_UIDS[0] - 1),
-            new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
-            /* Empty range between UIDS[1] and UIDS[2], should be excluded, */
-            new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
-        })), disallow);
+        final Set<Range<Integer>> disallow =
+                vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
+                        null /* allowedApplications */, Arrays.asList(packages));
+        assertEquals(rangeSet(
+                uidRange(userStart, userStart + PKG_UIDS[0] - 1),
+                uidRange(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[1] - 1),
+                /* Empty range between UIDS[1] and UIDS[2], should be excluded, */
+                uidRange(userStart + PKG_UIDS[2] + 1, userStop)),
+                disallow);
     }
 
     @Test
@@ -350,84 +365,86 @@
     @Test
     public void testLockdownChangingPackage() throws Exception {
         final Vpn vpn = createVpn(primaryUser.id);
-        final UidRange user = PRI_USER_RANGE;
-
+        final Range<Integer> user = PRI_USER_RANGE;
+        final int userStart = user.getLower();
+        final int userStop = user.getUpper();
         // Set always-on without lockdown.
         assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null));
 
         // Set always-on with lockdown.
         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)
+                new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
+                new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStop)
         }));
 
         // Switch to another app.
         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)
+                new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
+                new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStop)
         }));
         verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
-                new UidRangeParcel(user.start, user.start + PKG_UIDS[3] - 1),
-                new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop)
+                new UidRangeParcel(userStart, userStart + PKG_UIDS[3] - 1),
+                new UidRangeParcel(userStart + PKG_UIDS[3] + 1, userStop)
         }));
     }
 
     @Test
     public void testLockdownAllowlist() throws Exception {
         final Vpn vpn = createVpn(primaryUser.id);
-        final UidRange user = PRI_USER_RANGE;
-
+        final Range<Integer> user = PRI_USER_RANGE;
+        final int userStart = user.getLower();
+        final int userStop = user.getUpper();
         // Set always-on with lockdown and allow app PKGS[2] from lockdown.
         assertTrue(vpn.setAlwaysOnPackage(
                 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)
+        verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[]  {
+                new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
+                new UidRangeParcel(userStart + PKG_UIDS[2] + 1, userStop)
         }));
         // Change allowed app list to PKGS[3].
         assertTrue(vpn.setAlwaysOnPackage(
                 PKGS[1], true, Collections.singletonList(PKGS[3])));
         verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
-                new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop)
+                new UidRangeParcel(userStart + PKG_UIDS[2] + 1, userStop)
         }));
         verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
-                new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1),
-                new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop)
+                new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStart + PKG_UIDS[3] - 1),
+                new UidRangeParcel(userStart + PKG_UIDS[3] + 1, userStop)
         }));
 
         // Change the VPN app.
         assertTrue(vpn.setAlwaysOnPackage(
                 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)
+                new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
+                new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStart + PKG_UIDS[3] - 1)
         }));
         verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
-                new UidRangeParcel(user.start, user.start + PKG_UIDS[0] - 1),
-                new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1)
+                new UidRangeParcel(userStart, userStart + PKG_UIDS[0] - 1),
+                new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[3] - 1)
         }));
 
         // Remove the list of allowed packages.
         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)
+                new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[3] - 1),
+                new UidRangeParcel(userStart + PKG_UIDS[3] + 1, userStop)
         }));
         verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
-                new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.stop),
+                new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStop),
         }));
 
         // Add the list of allowed packages.
         assertTrue(vpn.setAlwaysOnPackage(
                 PKGS[0], true, Collections.singletonList(PKGS[1])));
         verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
-                new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.stop)
+                new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStop)
         }));
         verify(mConnectivityManager).setRequireVpnForUids(true, 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)
+                new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[1] - 1),
+                new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStop)
         }));
 
         // Try allowing a package with a comma, should be rejected.
@@ -439,12 +456,12 @@
         assertTrue(vpn.setAlwaysOnPackage(
                 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)
+                new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[1] - 1),
+                new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStop)
         }));
         verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
-                new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[2] - 1),
-                new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop)
+                new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[2] - 1),
+                new UidRangeParcel(userStart + PKG_UIDS[2] + 1, userStop)
         }));
     }
 
@@ -452,7 +469,7 @@
     public void testLockdownRuleRepeatability() throws Exception {
         final Vpn vpn = createVpn(primaryUser.id);
         final UidRangeParcel[] primaryUserRangeParcel = new UidRangeParcel[] {
-                new UidRangeParcel(PRI_USER_RANGE.start, PRI_USER_RANGE.stop)};
+                new UidRangeParcel(PRI_USER_RANGE.getLower(), PRI_USER_RANGE.getUpper())};
         // Given legacy lockdown is already enabled,
         vpn.setLockdown(true);
         verify(mConnectivityManager, times(1)).setRequireVpnForUids(true,
@@ -484,7 +501,7 @@
     public void testLockdownRuleReversibility() throws Exception {
         final Vpn vpn = createVpn(primaryUser.id);
         final UidRangeParcel[] entireUser = {
-            new UidRangeParcel(PRI_USER_RANGE.start, PRI_USER_RANGE.stop)
+            new UidRangeParcel(PRI_USER_RANGE.getLower(), PRI_USER_RANGE.getUpper())
         };
         final UidRangeParcel[] exceptPkg0 = {
             new UidRangeParcel(entireUser[0].start, entireUser[0].start + PKG_UIDS[0] - 1),
diff --git a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
index 5b17aad..8a0c923 100644
--- a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
@@ -109,16 +109,6 @@
     }
 
     @Test
-    public void testBuilderRequiresNonEmptyUnderlyingCaps() {
-        try {
-            newBuilder().addExposedCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET).build();
-
-            fail("Expected exception due to invalid required underlying capabilities");
-        } catch (IllegalArgumentException e) {
-        }
-    }
-
-    @Test
     public void testBuilderRequiresNonNullRetryInterval() {
         try {
             newBuilder().setRetryInterval(null);
diff --git a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
index 1ef1a61..631c862 100644
--- a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
@@ -328,7 +328,7 @@
     public void testRecordTrackerCallbackNotifiedForNetworkSuspended() {
         RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback();
 
-        cb.onNetworkSuspended(mNetwork);
+        cb.onCapabilitiesChanged(mNetwork, SUSPENDED_NETWORK_CAPABILITIES);
 
         UnderlyingNetworkRecord expectedRecord =
                 new UnderlyingNetworkRecord(
@@ -336,7 +336,11 @@
                         SUSPENDED_NETWORK_CAPABILITIES,
                         INITIAL_LINK_PROPERTIES,
                         false /* isBlocked */);
-        verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+        verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+        // onSelectedUnderlyingNetworkChanged() won't be fired twice if network capabilities doesn't
+        // change.
+        cb.onCapabilitiesChanged(mNetwork, SUSPENDED_NETWORK_CAPABILITIES);
+        verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
     }
 
     @Test
@@ -344,7 +348,7 @@
         RouteSelectionCallback cb =
                 verifyRegistrationOnAvailableAndGetCallback(SUSPENDED_NETWORK_CAPABILITIES);
 
-        cb.onNetworkResumed(mNetwork);
+        cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES);
 
         UnderlyingNetworkRecord expectedRecord =
                 new UnderlyingNetworkRecord(
@@ -352,7 +356,11 @@
                         INITIAL_NETWORK_CAPABILITIES,
                         INITIAL_LINK_PROPERTIES,
                         false /* isBlocked */);
-        verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+        verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+        // onSelectedUnderlyingNetworkChanged() won't be fired twice if network capabilities doesn't
+        // change.
+        cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES);
+        verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
     }
 
     @Test