Merge "Remove DisplayList.h dependency from Canvas.h"
diff --git a/.gitignore b/.gitignore
index c47cc8b..5018436 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,6 @@
 .idea
 *.iml
 *.sw*
-gen/
\ No newline at end of file
+gen/
+.vscode/
+*.code-workspace
diff --git a/Android.bp b/Android.bp
index 35f97ac..5c0dd63 100644
--- a/Android.bp
+++ b/Android.bp
@@ -532,6 +532,7 @@
         "android.hardware.vibrator-V1.2-java",
         "android.hardware.vibrator-V1.3-java",
         "android.security.apc-java",
+        "android.security.authorization-java",
         "android.system.keystore2-java",
         "android.system.suspend.control.internal-java",
         "cameraprotosnano",
diff --git a/apct-tests/perftests/OWNERS b/apct-tests/perftests/OWNERS
index a060ad9..7e7feaf 100644
--- a/apct-tests/perftests/OWNERS
+++ b/apct-tests/perftests/OWNERS
@@ -1,2 +1,11 @@
-timmurray@google.com
+balejs@google.com
+carmenjackson@google.com
+cfijalkovich@google.com
+dualli@google.com
+edgararriaga@google.com
+jpakaravoor@google.com
+kevinjeon@google.com
 philipcuadra@google.com
+shombert@google.com
+timmurray@google.com
+wessam@google.com
diff --git a/apex/appsearch/framework/api/current.txt b/apex/appsearch/framework/api/current.txt
index 9fa4b8e..2320b75 100644
--- a/apex/appsearch/framework/api/current.txt
+++ b/apex/appsearch/framework/api/current.txt
@@ -8,6 +8,7 @@
   }
 
   public class AppSearchManager {
+    method public void createGlobalSearchSession(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<android.app.appsearch.GlobalSearchSession>>);
     method public void createSearchSession(@NonNull android.app.appsearch.AppSearchManager.SearchContext, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<android.app.appsearch.AppSearchSession>>);
   }
 
@@ -80,7 +81,8 @@
     method @NonNull public android.app.appsearch.AppSearchSchema.PropertyConfig.Builder setTokenizerType(int);
   }
 
-  public final class AppSearchSession {
+  public final class AppSearchSession implements java.io.Closeable {
+    method public void close();
     method public void getByUri(@NonNull android.app.appsearch.GetByUriRequest, @NonNull java.util.concurrent.Executor, @NonNull android.app.appsearch.BatchResultCallback<java.lang.String,android.app.appsearch.GenericDocument>);
     method public void getSchema(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<java.util.Set<android.app.appsearch.AppSearchSchema>>>);
     method public void putDocuments(@NonNull android.app.appsearch.PutDocumentsRequest, @NonNull java.util.concurrent.Executor, @NonNull android.app.appsearch.BatchResultCallback<java.lang.String,java.lang.Void>);
@@ -149,6 +151,11 @@
     method @NonNull public android.app.appsearch.GetByUriRequest.Builder setNamespace(@NonNull String);
   }
 
+  public class GlobalSearchSession implements java.io.Closeable {
+    method public void close();
+    method @NonNull public android.app.appsearch.SearchResults query(@NonNull String, @NonNull android.app.appsearch.SearchSpec, @NonNull java.util.concurrent.Executor);
+  }
+
   public class PackageIdentifier {
     ctor public PackageIdentifier(@NonNull String, @NonNull byte[]);
     method @NonNull public String getPackageName();
diff --git a/apex/appsearch/framework/api/system-current.txt b/apex/appsearch/framework/api/system-current.txt
index 73a4a19..4a6194e 100644
--- a/apex/appsearch/framework/api/system-current.txt
+++ b/apex/appsearch/framework/api/system-current.txt
@@ -1,17 +1,9 @@
 // Signature format: 2.0
 package android.app.appsearch {
 
-  public class AppSearchManager {
-    method public void createGlobalSearchSession(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<android.app.appsearch.GlobalSearchSession>>);
-  }
-
   public class AppSearchManagerFrameworkInitializer {
     method public static void initialize();
   }
 
-  public class GlobalSearchSession {
-    method @NonNull public android.app.appsearch.SearchResults query(@NonNull String, @NonNull android.app.appsearch.SearchSpec, @NonNull java.util.concurrent.Executor);
-  }
-
 }
 
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
index a5b7080..6fa8f85 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
@@ -17,7 +17,6 @@
 
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
-import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.content.Context;
 import android.os.Bundle;
@@ -123,8 +122,8 @@
     /**
      * Creates a new {@link AppSearchSession}.
      *
-     * <p>This process requires an AppSearch native indexing file system for each user. If it's not
-     * created for this user, the initialization process will create one under user's directory.
+     * <p>This process requires an AppSearch native indexing file system. If it's not created, the
+     * initialization process will create one under the user's credential encrypted directory.
      *
      * @param searchContext The {@link SearchContext} contains all information to create a new
      *                      {@link AppSearchSession}
@@ -147,16 +146,14 @@
     /**
      * Creates a new {@link GlobalSearchSession}.
      *
-     * <p>This process requires an AppSearch native indexing file system for each user. If it's not
-     * created for this user, the initialization process will create one under user's directory.
+     * <p>This process requires an AppSearch native indexing file system. If it's not created, the
+     * initialization process will create one under the user's credential encrypted directory.
      *
      * @param executor      Executor on which to invoke the callback.
      * @param callback      The {@link AppSearchResult}&lt;{@link GlobalSearchSession}&gt; of
      *                      performing this operation. Or a {@link AppSearchResult} with failure
      *                      reason code and error information.
-     * @hide
      */
-    @SystemApi
     public void createGlobalSearchSession(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull Consumer<AppSearchResult<GlobalSearchSession>> callback) {
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
index d4872e8..0427577 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
@@ -28,6 +28,7 @@
 
 import com.android.internal.util.Preconditions;
 
+import java.io.Closeable;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -42,7 +43,7 @@
  *
  * This class is thread safe.
  */
-public final class AppSearchSession {
+public final class AppSearchSession implements Closeable {
     private static final String TAG = "AppSearchSession";
     private final String mDatabaseName;
     @UserIdInt
@@ -490,11 +491,10 @@
     }
 
     /**
-     * Closes the SearchSessionImpl to persists all update/delete requests to the disk.
-     *
-     * @hide
+     * Closes the {@link AppSearchSession} to persist all schema and document updates, additions,
+     * and deletes to disk.
      */
-    // TODO(b/175637134) when unhide it, implement Closeable and remove this method.
+    @Override
     public void close() {
         if (mIsMutated && !mIsClosed) {
             try {
diff --git a/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java
index 95f7d79..e4e030e 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java
@@ -19,10 +19,12 @@
 
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
-import android.annotation.SystemApi;
 import android.annotation.UserIdInt;
 import android.os.RemoteException;
 
+import com.android.internal.util.Preconditions;
+
+import java.io.Closeable;
 import java.util.Objects;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
@@ -31,14 +33,13 @@
  * This class provides global access to the centralized AppSearch index maintained by the system.
  *
  * <p>Apps can retrieve indexed documents through the query API.
- * @hide
  */
-@SystemApi
-public class GlobalSearchSession {
+public class GlobalSearchSession implements Closeable {
 
     private final IAppSearchManager mService;
     @UserIdInt
     private final int mUserId;
+    private boolean mIsClosed = false;
 
     static void createGlobalSearchSession(
             @NonNull IAppSearchManager service,
@@ -129,7 +130,14 @@
         Objects.requireNonNull(queryExpression);
         Objects.requireNonNull(searchSpec);
         Objects.requireNonNull(executor);
+        Preconditions.checkState(!mIsClosed, "GlobalSearchSession has already been closed");
         return new SearchResults(mService, /*databaseName=*/null, queryExpression,
                 searchSpec, mUserId, executor);
     }
+
+    /** Closes the {@link GlobalSearchSession}. */
+    @Override
+    public void close() {
+        mIsClosed = true;
+    }
 }
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java b/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java
index 4931cc0..62324b2 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java
@@ -52,6 +52,9 @@
     /** @hide */
     public static final String PACKAGE_NAME_FIELD = "packageName";
 
+    /** @hide */
+    public static final String DATABASE_NAME_FIELD = "databaseName";
+
     @NonNull private final Bundle mBundle;
 
     /** Cache of the inflated document. Comes from inflating mDocumentBundle at first use. */
@@ -119,6 +122,17 @@
     }
 
     /**
+     * Contains the database name that stored the {@link GenericDocument}.
+     *
+     * @return Database name that stored the document
+     * @hide
+     */
+    @NonNull
+    public String getDatabaseName() {
+        return Preconditions.checkNotNull(mBundle.getString(DATABASE_NAME_FIELD));
+    }
+
+    /**
      * This class represents a match objects for any Snippets that might be present in {@link
      * SearchResults} from query. Using this class user can get the full text, exact matches and
      * Snippets of document content for a given match.
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 b754926..674f199 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
@@ -45,6 +45,7 @@
 import com.google.android.icing.proto.GetAllNamespacesResultProto;
 import com.google.android.icing.proto.GetOptimizeInfoResultProto;
 import com.google.android.icing.proto.GetResultProto;
+import com.google.android.icing.proto.GetResultSpecProto;
 import com.google.android.icing.proto.GetSchemaResultProto;
 import com.google.android.icing.proto.IcingSearchEngineOptions;
 import com.google.android.icing.proto.InitializeResultProto;
@@ -62,6 +63,7 @@
 import com.google.android.icing.proto.SearchSpecProto;
 import com.google.android.icing.proto.SetSchemaResultProto;
 import com.google.android.icing.proto.StatusProto;
+import com.google.android.icing.proto.TypePropertyMask;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -432,7 +434,9 @@
         try {
             getResultProto =
                     mIcingSearchEngineLocked.get(
-                            createPrefix(packageName, databaseName) + namespace, uri);
+                            createPrefix(packageName, databaseName) + namespace,
+                            uri,
+                            GetResultSpecProto.getDefaultInstance());
         } finally {
             mReadWriteLock.readLock().unlock();
         }
@@ -691,8 +695,6 @@
      * <p>If the app crashes before a call to PersistToDisk(), Icing would trigger a costly recovery
      * process in next initialization. After that, Icing would still be able to recover all written
      * data.
-     *
-     * @throws AppSearchException
      */
     public void persistToDisk() throws AppSearchException {
         PersistToDiskResultProto persistToDiskResultProto =
@@ -986,13 +988,12 @@
             return false;
         }
 
-        List<ResultSpecProto.TypePropertyMask> prefixedTypePropertyMasks = new ArrayList<>();
+        List<TypePropertyMask> prefixedTypePropertyMasks = new ArrayList<>();
         // Rewrite filters to include a database prefix.
         for (String prefix : existingPrefixes) {
             Set<String> existingSchemaTypes = mSchemaMapLocked.get(prefix);
             // Qualify the given schema types
-            for (ResultSpecProto.TypePropertyMask typePropertyMask :
-                    resultSpecBuilder.getTypePropertyMasksList()) {
+            for (TypePropertyMask typePropertyMask : resultSpecBuilder.getTypePropertyMasksList()) {
                 String qualifiedType = prefix + typePropertyMask.getSchemaType();
                 if (existingSchemaTypes.contains(qualifiedType)) {
                     prefixedTypePropertyMasks.add(
@@ -1060,12 +1061,36 @@
         int delimiterIndex = prefix.indexOf(PACKAGE_DELIMITER);
         if (delimiterIndex == -1) {
             // This should never happen if we construct our prefixes properly
-            Log.wtf(TAG, "Malformed prefix doesn't contain package name: " + prefix);
+            Log.wtf(TAG, "Malformed prefix doesn't contain package delimiter: " + prefix);
             return "";
         }
         return prefix.substring(0, delimiterIndex);
     }
 
+    /**
+     * Returns the database name that's contained within the {@code prefix}.
+     *
+     * @param prefix Prefix string that contains the database name inside of it. The database name
+     *     must be between the {@link #PACKAGE_DELIMITER} and {@link #DATABASE_DELIMITER}
+     * @return Valid database name.
+     */
+    @NonNull
+    private static String getDatabaseName(@NonNull String prefix) {
+        int packageDelimiterIndex = prefix.indexOf(PACKAGE_DELIMITER);
+        int databaseDelimiterIndex = prefix.indexOf(DATABASE_DELIMITER);
+        if (packageDelimiterIndex == -1) {
+            // This should never happen if we construct our prefixes properly
+            Log.wtf(TAG, "Malformed prefix doesn't contain package delimiter: " + prefix);
+            return "";
+        }
+        if (databaseDelimiterIndex == -1) {
+            // This should never happen if we construct our prefixes properly
+            Log.wtf(TAG, "Malformed prefix doesn't contain database delimiter: " + prefix);
+            return "";
+        }
+        return prefix.substring(packageDelimiterIndex + 1, databaseDelimiterIndex);
+    }
+
     @NonNull
     private static String removePrefix(@NonNull String prefixedString) throws AppSearchException {
         // The prefix is made up of the package, then the database. So we only need to find the
@@ -1178,6 +1203,9 @@
         // Parallel array of package names for each document search result.
         List<String> packageNames = new ArrayList<>(searchResultProto.getResultsCount());
 
+        // Parallel array of database names for each document search result.
+        List<String> databaseNames = new ArrayList<>(searchResultProto.getResultsCount());
+
         SearchResultProto.Builder resultsBuilder = searchResultProto.toBuilder();
         for (int i = 0; i < searchResultProto.getResultsCount(); i++) {
             SearchResultProto.ResultProto.Builder resultBuilder =
@@ -1185,10 +1213,12 @@
             DocumentProto.Builder documentBuilder = resultBuilder.getDocument().toBuilder();
             String prefix = removePrefixesFromDocument(documentBuilder);
             packageNames.add(getPackageName(prefix));
+            databaseNames.add(getDatabaseName(prefix));
             resultBuilder.setDocument(documentBuilder);
             resultsBuilder.setResults(i, resultBuilder);
         }
-        return SearchResultToProtoConverter.toSearchResultPage(resultsBuilder, packageNames);
+        return SearchResultToProtoConverter.toSearchResultPage(
+                resultsBuilder, packageNames, databaseNames);
     }
 
     @GuardedBy("mReadWriteLock")
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java
index ccd567d..f422ebc 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java
@@ -46,11 +46,16 @@
      * @param proto The {@link SearchResultProto} containing results.
      * @param packageNames A parallel array of package names. The package name at index 'i' of this
      *     list should be the package that indexed the document at index 'i' of proto.getResults(i).
+     * @param databaseNames A parallel array of database names. The database name at index 'i' of
+     *     this list shold be the database that indexed the document at index 'i' of
+     *     proto.getResults(i).
      * @return {@link SearchResultPage} of results.
      */
     @NonNull
     public static SearchResultPage toSearchResultPage(
-            @NonNull SearchResultProtoOrBuilder proto, @NonNull List<String> packageNames) {
+            @NonNull SearchResultProtoOrBuilder proto,
+            @NonNull List<String> packageNames,
+            @NonNull List<String> databaseNames) {
         Preconditions.checkArgument(
                 proto.getResultsCount() == packageNames.size(),
                 "Size of " + "results does not match the number of package names.");
@@ -58,7 +63,9 @@
         bundle.putLong(SearchResultPage.NEXT_PAGE_TOKEN_FIELD, proto.getNextPageToken());
         ArrayList<Bundle> resultBundles = new ArrayList<>(proto.getResultsCount());
         for (int i = 0; i < proto.getResultsCount(); i++) {
-            resultBundles.add(toSearchResultBundle(proto.getResults(i), packageNames.get(i)));
+            resultBundles.add(
+                    toSearchResultBundle(
+                            proto.getResults(i), packageNames.get(i), databaseNames.get(i)));
         }
         bundle.putParcelableArrayList(SearchResultPage.RESULTS_FIELD, resultBundles);
         return new SearchResultPage(bundle);
@@ -69,16 +76,20 @@
      *
      * @param proto The proto to be converted.
      * @param packageName The package name associated with the document in {@code proto}.
+     * @param databaseName The database name associated with the document in {@code proto}.
      * @return A {@link SearchResult} bundle.
      */
     @NonNull
     private static Bundle toSearchResultBundle(
-            @NonNull SearchResultProto.ResultProtoOrBuilder proto, @NonNull String packageName) {
+            @NonNull SearchResultProto.ResultProtoOrBuilder proto,
+            @NonNull String packageName,
+            @NonNull String databaseName) {
         Bundle bundle = new Bundle();
         GenericDocument document =
                 GenericDocumentToProtoConverter.toGenericDocument(proto.getDocument());
         bundle.putBundle(SearchResult.DOCUMENT_FIELD, document.getBundle());
         bundle.putString(SearchResult.PACKAGE_NAME_FIELD, packageName);
+        bundle.putString(SearchResult.DATABASE_NAME_FIELD, databaseName);
 
         ArrayList<Bundle> matchList = new ArrayList<>();
         if (proto.hasSnippet()) {
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchSpecToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchSpecToProtoConverter.java
index 073a7f6..0d7d3e1 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchSpecToProtoConverter.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchSpecToProtoConverter.java
@@ -25,6 +25,7 @@
 import com.google.android.icing.proto.ScoringSpecProto;
 import com.google.android.icing.proto.SearchSpecProto;
 import com.google.android.icing.proto.TermMatchType;
+import com.google.android.icing.proto.TypePropertyMask;
 
 import java.util.List;
 import java.util.Map;
@@ -71,7 +72,7 @@
         Map<String, List<String>> projectionTypePropertyPaths = spec.getProjections();
         for (Map.Entry<String, List<String>> e : projectionTypePropertyPaths.entrySet()) {
             builder.addTypePropertyMasks(
-                    ResultSpecProto.TypePropertyMask.newBuilder()
+                    TypePropertyMask.newBuilder()
                             .setSchemaType(e.getKey())
                             .addAllPaths(e.getValue()));
         }
@@ -107,8 +108,7 @@
             case SearchSpec.RANKING_STRATEGY_CREATION_TIMESTAMP:
                 return ScoringSpecProto.RankingStrategy.Code.CREATION_TIMESTAMP;
             case SearchSpec.RANKING_STRATEGY_RELEVANCE_SCORE:
-                return ScoringSpecProto.RankingStrategy.Code
-                        .RELEVANCE_SCORE_NONFUNCTIONAL_PLACEHOLDER;
+                return ScoringSpecProto.RankingStrategy.Code.RELEVANCE_SCORE;
             default:
                 throw new IllegalArgumentException(
                         "Invalid result ranking strategy: " + rankingStrategyCode);
diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt
index f8e5a8a..9be3049 100644
--- a/apex/appsearch/synced_jetpack_changeid.txt
+++ b/apex/appsearch/synced_jetpack_changeid.txt
@@ -1 +1 @@
-I6745091e5cb97d69ce2e5f85d3d15c073e7e3ef7
+Icd58005ad659b6b3d03f683f8954939175324685
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShimImpl.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShimImpl.java
index 6859747..39ca687 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShimImpl.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShimImpl.java
@@ -62,6 +62,7 @@
             @NonNull GlobalSearchSession session, @NonNull ExecutorService executor) {
         mGlobalSearchSession = Preconditions.checkNotNull(session);
         mExecutor = Preconditions.checkNotNull(executor);
+
     }
 
     @NonNull
@@ -72,4 +73,9 @@
                 mGlobalSearchSession.query(queryExpression, searchSpec, mExecutor);
         return new SearchResultsShimImpl(searchResults, mExecutor);
     }
+
+    @Override
+    public void close() {
+        mGlobalSearchSession.close();
+    }
 }
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java
index e439c5a..3e81968 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java
@@ -21,6 +21,7 @@
 
 import com.google.common.util.concurrent.ListenableFuture;
 
+import java.io.Closeable;
 import java.util.Set;
 
 /**
@@ -29,7 +30,7 @@
  *
  * <p>All implementations of this interface must be thread safe.
  */
-public interface AppSearchSessionShim {
+public interface AppSearchSessionShim extends Closeable {
 
     /**
      * Sets the schema that will be used by documents provided to the {@link #putDocuments} method.
@@ -207,11 +208,9 @@
             @NonNull String queryExpression, @NonNull SearchSpec searchSpec);
 
     /**
-     * Closes the SearchSessionImpl to persists all update/delete requests to the disk.
-     *
-     * @hide
+     * Closes the {@link AppSearchSessionShim} to persist all schema and document updates,
+     * additions, and deletes to disk.
      */
-
-    // TODO(b/175637134) when unhide it, extends Closeable and remove this method.
+    @Override
     void close();
 }
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/GlobalSearchSessionShim.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/GlobalSearchSessionShim.java
index 2d09247..cd867a4 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/GlobalSearchSessionShim.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/GlobalSearchSessionShim.java
@@ -18,12 +18,14 @@
 
 import android.annotation.NonNull;
 
+import java.io.Closeable;
+
 /**
  * This class provides global access to the centralized AppSearch index maintained by the system.
  *
  * <p>Apps can retrieve indexed documents through the query API.
  */
-public interface GlobalSearchSessionShim {
+public interface GlobalSearchSessionShim extends Closeable {
     /**
      * Searches across all documents in the storage based on a given query string.
      *
@@ -65,4 +67,8 @@
      */
     @NonNull
     SearchResultsShim query(@NonNull String queryExpression, @NonNull SearchSpec searchSpec);
+
+    /** Closes the {@link GlobalSearchSessionShim}. */
+    @Override
+    void close();
 }
diff --git a/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java b/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java
index 18643ed..4441643 100644
--- a/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java
@@ -16,6 +16,8 @@
 
 package com.android.server;
 
+import android.app.BroadcastOptions;
+
 import com.android.server.deviceidle.IDeviceIdleConstraint;
 
 public interface DeviceIdleInternal {
@@ -32,8 +34,17 @@
     void addPowerSaveTempWhitelistApp(int callingUid, String packageName,
             long duration, int userId, boolean sync, String reason);
 
-    // duration in milliseconds
-    void addPowerSaveTempWhitelistAppDirect(int uid, long duration, boolean sync,
+    /**
+     * Called by ActivityManagerService to directly add UID to DeviceIdleController's temp
+     * allowlist.
+     * @param uid
+     * @param duration duration in milliseconds
+     * @param type temp allowlist type defined at {@link BroadcastOptions.TempAllowListType}
+     * @param sync
+     * @param reason
+     */
+    void addPowerSaveTempWhitelistAppDirect(int uid, long duration,
+            @BroadcastOptions.TempAllowListType int type, boolean sync,
             String reason);
 
     // duration in milliseconds
diff --git a/apex/jobscheduler/framework/java/com/android/server/PowerAllowlistInternal.java b/apex/jobscheduler/framework/java/com/android/server/PowerAllowlistInternal.java
new file mode 100644
index 0000000..b5d1838
--- /dev/null
+++ b/apex/jobscheduler/framework/java/com/android/server/PowerAllowlistInternal.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import android.annotation.NonNull;
+
+public interface PowerAllowlistInternal {
+    /**
+     * Listener to be notified when the temporary allowlist changes.
+     */
+    interface TempAllowlistChangeListener {
+        void onAppAdded(int uid);
+        void onAppRemoved(int uid);
+    }
+
+    /**
+     * Registers a listener that will be notified when the temp allowlist changes.
+     */
+    void registerTempAllowlistChangeListener(@NonNull TempAllowlistChangeListener listener);
+
+    /**
+     * Unregisters a registered stationary listener from being notified when the temp allowlist
+     * changes.
+     */
+    void unregisterTempAllowlistChangeListener(@NonNull TempAllowlistChangeListener listener);
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index 9989252..7aed32c 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -17,9 +17,12 @@
 package com.android.server;
 
 import android.Manifest;
+import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.AlarmManager;
+import android.app.BroadcastOptions;
+import android.app.BroadcastOptions.TempAllowListType;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -558,6 +561,9 @@
     private final ArraySet<DeviceIdleInternal.StationaryListener> mStationaryListeners =
             new ArraySet<>();
 
+    private final ArraySet<PowerAllowlistInternal.TempAllowlistChangeListener>
+            mTempAllowlistChangeListeners = new ArraySet<>();
+
     private static final int EVENT_NULL = 0;
     private static final int EVENT_NORMAL = 1;
     private static final int EVENT_LIGHT_IDLE = 2;
@@ -741,6 +747,20 @@
         }
     }
 
+    private void registerTempAllowlistChangeListener(
+            @NonNull PowerAllowlistInternal.TempAllowlistChangeListener listener) {
+        synchronized (this) {
+            mTempAllowlistChangeListeners.add(listener);
+        }
+    }
+
+    private void unregisterTempAllowlistChangeListener(
+            @NonNull PowerAllowlistInternal.TempAllowlistChangeListener listener) {
+        synchronized (this) {
+            mTempAllowlistChangeListeners.remove(listener);
+        }
+    }
+
     @VisibleForTesting
     final class MotionListener extends TriggerEventListener
             implements SensorEventListener {
@@ -1508,12 +1528,13 @@
     @VisibleForTesting
     static final int MSG_REPORT_STATIONARY_STATUS = 7;
     private static final int MSG_FINISH_IDLE_OP = 8;
-    private static final int MSG_REPORT_TEMP_APP_WHITELIST_CHANGED = 9;
+    private static final int MSG_REPORT_TEMP_APP_WHITELIST_CHANGED_TO_NPMS = 9;
     private static final int MSG_SEND_CONSTRAINT_MONITORING = 10;
     @VisibleForTesting
     static final int MSG_UPDATE_PRE_IDLE_TIMEOUT_FACTOR = 11;
     @VisibleForTesting
     static final int MSG_RESET_PRE_IDLE_TIMEOUT_FACTOR = 12;
+    private static final int MSG_REPORT_TEMP_APP_WHITELIST_CHANGED = 13;
 
     final class MyHandler extends Handler {
         MyHandler(Looper looper) {
@@ -1606,14 +1627,31 @@
                 } break;
                 case MSG_TEMP_APP_WHITELIST_TIMEOUT: {
                     // TODO: What is keeping the device awake at this point? Does it need to be?
-                    int appId = msg.arg1;
-                    checkTempAppWhitelistTimeout(appId);
+                    int uid = msg.arg1;
+                    checkTempAppWhitelistTimeout(uid);
                 } break;
                 case MSG_FINISH_IDLE_OP: {
                     // mActiveIdleWakeLock is held at this point
                     decActiveIdleOps();
                 } break;
                 case MSG_REPORT_TEMP_APP_WHITELIST_CHANGED: {
+                    final int uid = msg.arg1;
+                    final boolean added = (msg.arg2 == 1);
+                    PowerAllowlistInternal.TempAllowlistChangeListener[] listeners;
+                    synchronized (DeviceIdleController.this) {
+                        listeners = mTempAllowlistChangeListeners.toArray(
+                                new PowerAllowlistInternal.TempAllowlistChangeListener[
+                                        mTempAllowlistChangeListeners.size()]);
+                    }
+                    for (PowerAllowlistInternal.TempAllowlistChangeListener listener : listeners) {
+                        if (added) {
+                            listener.onAppAdded(uid);
+                        } else {
+                            listener.onAppRemoved(uid);
+                        }
+                    }
+                } break;
+                case MSG_REPORT_TEMP_APP_WHITELIST_CHANGED_TO_NPMS: {
                     final int appId = msg.arg1;
                     final boolean added = (msg.arg2 == 1);
                     mNetworkPolicyManagerInternal.onTempPowerSaveWhitelistChange(appId, added);
@@ -1905,9 +1943,9 @@
 
         // duration in milliseconds
         @Override
-        public void addPowerSaveTempWhitelistAppDirect(int uid, long duration, boolean sync,
-                String reason) {
-            addPowerSaveTempWhitelistAppDirectInternal(0, uid, duration, sync, reason);
+        public void addPowerSaveTempWhitelistAppDirect(int uid, long duration,
+                @TempAllowListType int type, boolean sync, String reason) {
+            addPowerSaveTempWhitelistAppDirectInternal(0, uid, duration, type, sync, reason);
         }
 
         // duration in milliseconds
@@ -1960,6 +1998,21 @@
         }
     }
 
+    private class LocalPowerAllowlistService implements PowerAllowlistInternal {
+
+        @Override
+        public void registerTempAllowlistChangeListener(
+                @NonNull TempAllowlistChangeListener listener) {
+            DeviceIdleController.this.registerTempAllowlistChangeListener(listener);
+        }
+
+        @Override
+        public void unregisterTempAllowlistChangeListener(
+                @NonNull TempAllowlistChangeListener listener) {
+            DeviceIdleController.this.unregisterTempAllowlistChangeListener(listener);
+        }
+    }
+
     static class Injector {
         private final Context mContext;
         private ConnectivityManager mConnectivityManager;
@@ -2164,6 +2217,7 @@
         publishBinderService(Context.DEVICE_IDLE_CONTROLLER, mBinderService);
         mLocalService = new LocalService();
         publishLocalService(DeviceIdleInternal.class, mLocalService);
+        publishLocalService(PowerAllowlistInternal.class, new LocalPowerAllowlistService());
     }
 
     @Override
@@ -2667,7 +2721,9 @@
             long duration, int userId, boolean sync, String reason) {
         try {
             int uid = getContext().getPackageManager().getPackageUidAsUser(packageName, userId);
-            addPowerSaveTempWhitelistAppDirectInternal(callingUid, uid, duration, sync, reason);
+            addPowerSaveTempWhitelistAppDirectInternal(callingUid, uid, duration,
+                    BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED, sync,
+                    reason);
         } catch (NameNotFoundException e) {
         }
     }
@@ -2677,7 +2733,7 @@
      * app an exemption to access network and acquire wakelocks.
      */
     void addPowerSaveTempWhitelistAppDirectInternal(int callingUid, int uid,
-            long duration, boolean sync, String reason) {
+            long duration, @TempAllowListType int type, boolean sync, String reason) {
         final long timeNow = SystemClock.elapsedRealtime();
         boolean informWhitelistChanged = false;
         int appId = UserHandle.getAppId(uid);
@@ -2708,15 +2764,18 @@
                             reason, uid);
                 } catch (RemoteException e) {
                 }
-                postTempActiveTimeoutMessage(appId, duration);
-                updateTempWhitelistAppIdsLocked(appId, true);
+                postTempActiveTimeoutMessage(uid, duration);
+                updateTempWhitelistAppIdsLocked(uid, true, duration, type);
                 if (sync) {
                     informWhitelistChanged = true;
                 } else {
-                    mHandler.obtainMessage(MSG_REPORT_TEMP_APP_WHITELIST_CHANGED, appId, 1)
+                    // NPMS needs to update its state synchronously in certain situations so we
+                    // can't have it use the TempAllowlistChangeListener path right now.
+                    // TODO: see if there's a way to simplify/consolidate
+                    mHandler.obtainMessage(MSG_REPORT_TEMP_APP_WHITELIST_CHANGED_TO_NPMS, appId, 1)
                             .sendToTarget();
                 }
-                reportTempWhitelistChangedLocked();
+                reportTempWhitelistChangedLocked(uid, true);
             }
         }
         if (informWhitelistChanged) {
@@ -2731,13 +2790,13 @@
         try {
             final int uid = getContext().getPackageManager().getPackageUidAsUser(
                     packageName, userId);
-            final int appId = UserHandle.getAppId(uid);
-            removePowerSaveTempWhitelistAppDirectInternal(appId);
+            removePowerSaveTempWhitelistAppDirectInternal(uid);
         } catch (NameNotFoundException e) {
         }
     }
 
-    private void removePowerSaveTempWhitelistAppDirectInternal(int appId) {
+    private void removePowerSaveTempWhitelistAppDirectInternal(int uid) {
+        final int appId = UserHandle.getAppId(uid);
         synchronized (this) {
             final int idx = mTempWhitelistAppIdEndTimes.indexOfKey(appId);
             if (idx < 0) {
@@ -2746,51 +2805,54 @@
             }
             final String reason = mTempWhitelistAppIdEndTimes.valueAt(idx).second;
             mTempWhitelistAppIdEndTimes.removeAt(idx);
-            onAppRemovedFromTempWhitelistLocked(appId, reason);
+            onAppRemovedFromTempWhitelistLocked(uid, reason);
         }
     }
 
-    private void postTempActiveTimeoutMessage(int appId, long delay) {
+    private void postTempActiveTimeoutMessage(int uid, long delay) {
         if (DEBUG) {
-            Slog.d(TAG, "postTempActiveTimeoutMessage: appId=" + appId + ", delay=" + delay);
+            Slog.d(TAG, "postTempActiveTimeoutMessage: uid=" + uid + ", delay=" + delay);
         }
         mHandler.sendMessageDelayed(
-                mHandler.obtainMessage(MSG_TEMP_APP_WHITELIST_TIMEOUT, appId, 0), delay);
+                mHandler.obtainMessage(MSG_TEMP_APP_WHITELIST_TIMEOUT, uid, 0), delay);
     }
 
-    void checkTempAppWhitelistTimeout(int appId) {
+    void checkTempAppWhitelistTimeout(int uid) {
         final long timeNow = SystemClock.elapsedRealtime();
+        final int appId = UserHandle.getAppId(uid);
         if (DEBUG) {
-            Slog.d(TAG, "checkTempAppWhitelistTimeout: appId=" + appId + ", timeNow=" + timeNow);
+            Slog.d(TAG, "checkTempAppWhitelistTimeout: uid=" + uid + ", timeNow=" + timeNow);
         }
         synchronized (this) {
-            Pair<MutableLong, String> entry = mTempWhitelistAppIdEndTimes.get(appId);
+            Pair<MutableLong, String> entry =
+                    mTempWhitelistAppIdEndTimes.get(appId);
             if (entry == null) {
                 // Nothing to do
                 return;
             }
             if (timeNow >= entry.first.value) {
                 mTempWhitelistAppIdEndTimes.delete(appId);
-                onAppRemovedFromTempWhitelistLocked(appId, entry.second);
+                onAppRemovedFromTempWhitelistLocked(uid, entry.second);
             } else {
                 // Need more time
                 if (DEBUG) {
-                    Slog.d(TAG, "Time to remove AppId " + appId + ": " + entry.first.value);
+                    Slog.d(TAG, "Time to remove uid " + uid + ": " + entry.first.value);
                 }
-                postTempActiveTimeoutMessage(appId, entry.first.value - timeNow);
+                postTempActiveTimeoutMessage(uid, entry.first.value - timeNow);
             }
         }
     }
 
     @GuardedBy("this")
-    private void onAppRemovedFromTempWhitelistLocked(int appId, String reason) {
+    private void onAppRemovedFromTempWhitelistLocked(int uid, String reason) {
         if (DEBUG) {
-            Slog.d(TAG, "Removing appId " + appId + " from temp whitelist");
+            Slog.d(TAG, "Removing uid " + uid + " from temp whitelist");
         }
-        updateTempWhitelistAppIdsLocked(appId, false);
+        final int appId = UserHandle.getAppId(uid);
+        updateTempWhitelistAppIdsLocked(uid, false, 0, 0);
         mHandler.obtainMessage(MSG_REPORT_TEMP_APP_WHITELIST_CHANGED, appId, 0)
                 .sendToTarget();
-        reportTempWhitelistChangedLocked();
+        reportTempWhitelistChangedLocked(uid, false);
         try {
             mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_TEMP_WHITELIST_FINISH,
                     reason, appId);
@@ -3811,7 +3873,16 @@
         passWhiteListsToForceAppStandbyTrackerLocked();
     }
 
-    private void updateTempWhitelistAppIdsLocked(int appId, boolean adding) {
+    /**
+     * update temp allowlist.
+     * @param uid uid to add or remove from temp allowlist.
+     * @param adding true to add to temp allowlist, false to remove from temp allowlist.
+     * @param durationMs duration in milliseconds to add to temp allowlist, only valid when
+     *                   param adding is true.
+     * @param type temp allowlist type defined at {@link BroadcastOptions.TempAllowListType}
+     */
+    private void updateTempWhitelistAppIdsLocked(int uid, boolean adding, long durationMs,
+            @TempAllowListType int type) {
         final int size = mTempWhitelistAppIdEndTimes.size();
         if (mTempWhitelistAppIdArray.length != size) {
             mTempWhitelistAppIdArray = new int[size];
@@ -3824,8 +3895,8 @@
                 Slog.d(TAG, "Setting activity manager temp whitelist to "
                         + Arrays.toString(mTempWhitelistAppIdArray));
             }
-            mLocalActivityManager.updateDeviceIdleTempWhitelist(mTempWhitelistAppIdArray, appId,
-                    adding);
+            mLocalActivityManager.updateDeviceIdleTempWhitelist(mTempWhitelistAppIdArray, uid,
+                    adding, durationMs, type);
         }
         if (mLocalPowerManager != null) {
             if (DEBUG) {
@@ -3843,7 +3914,9 @@
         getContext().sendBroadcastAsUser(intent, UserHandle.SYSTEM);
     }
 
-    private void reportTempWhitelistChangedLocked() {
+    private void reportTempWhitelistChangedLocked(final int uid, final boolean added) {
+        mHandler.obtainMessage(MSG_REPORT_TEMP_APP_WHITELIST_CHANGED, uid, added ? 1 : 0)
+                .sendToTarget();
         Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_TEMP_WHITELIST_CHANGED);
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
         getContext().sendBroadcastAsUser(intent, UserHandle.SYSTEM);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index a9ca730..26b5abe 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -260,11 +260,9 @@
             try {
                 final int bindFlags;
                 if (job.shouldTreatAsExpeditedJob()) {
-                    // Add BIND_FOREGROUND_SERVICE to make it BFGS. Without it, it'll be
-                    // PROCESS_STATE_IMPORTANT_FOREGROUND. Unclear which is better here.
                     // TODO(171305774): The job should run on the little cores. We'll probably need
                     // another binding flag for that.
-                    bindFlags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;
+                    bindFlags = Context.BIND_AUTO_CREATE;
                 } else {
                     bindFlags = Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
                             | Context.BIND_NOT_PERCEPTIBLE;
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index a02f8de..736ee18 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
@@ -60,6 +60,7 @@
 import android.util.SparseArray;
 import android.util.SparseArrayMap;
 import android.util.SparseBooleanArray;
+import android.util.SparseLongArray;
 import android.util.SparseSetArray;
 import android.util.proto.ProtoOutputStream;
 
@@ -68,6 +69,7 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.server.JobSchedulerBackgroundThread;
 import com.android.server.LocalServices;
+import com.android.server.PowerAllowlistInternal;
 import com.android.server.job.ConstantsProto;
 import com.android.server.job.JobSchedulerService;
 import com.android.server.job.JobServiceContext;
@@ -343,6 +345,15 @@
      */
     private final ArraySet<JobStatus> mTopStartedJobs = new ArraySet<>();
 
+    /** Current set of UIDs on the temp allowlist. */
+    private final SparseBooleanArray mTempAllowlistCache = new SparseBooleanArray();
+
+    /**
+     * Mapping of app IDs to the when their temp allowlist grace period ends (in the elapsed
+     * realtime timebase).
+     */
+    private final SparseLongArray mTempAllowlistGraceCache = new SparseLongArray();
+
     private final ActivityManagerInternal mActivityManagerInternal;
     private final AlarmManager mAlarmManager;
     private final ChargingTracker mChargeTracker;
@@ -538,6 +549,9 @@
      */
     private long mEJRewardNotificationSeenMs = QcConstants.DEFAULT_EJ_REWARD_NOTIFICATION_SEEN_MS;
 
+    private long mEJTempAllowlistGracePeriodMs =
+            QcConstants.DEFAULT_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS;
+
     /** The package verifier app. */
     @Nullable
     private String mPackageVerifier;
@@ -562,6 +576,9 @@
      * userId will the first arg.
      */
     private static final int MSG_PROCESS_USAGE_EVENT = 5;
+    /** A UID's free quota grace period has ended. */
+    @VisibleForTesting
+    static final int MSG_END_GRACE_PERIOD = 6;
 
     public QuotaController(@NonNull JobSchedulerService service,
             @NonNull BackgroundJobsController backgroundJobsController,
@@ -586,6 +603,9 @@
         UsageStatsManagerInternal usmi = LocalServices.getService(UsageStatsManagerInternal.class);
         usmi.registerListener(new UsageEventTracker());
 
+        PowerAllowlistInternal pai = LocalServices.getService(PowerAllowlistInternal.class);
+        pai.registerTempAllowlistChangeListener(new TempAllowlistTracker());
+
         try {
             ActivityManager.getService().registerUidObserver(mUidObserver,
                     ActivityManager.UID_OBSERVER_PROCSTATE,
@@ -693,6 +713,8 @@
         clearAppStatsLocked(UserHandle.getUserId(uid), packageName);
         mForegroundUids.delete(uid);
         mUidToPackageCache.remove(uid);
+        mTempAllowlistCache.delete(uid);
+        mTempAllowlistGraceCache.delete(uid);
     }
 
     @Override
@@ -1988,10 +2010,15 @@
         }
 
         private boolean shouldTrackLocked() {
+            final long nowElapsed = sElapsedRealtimeClock.millis();
             final int standbyBucket = JobSchedulerService.standbyBucketForPackage(mPkg.packageName,
-                    mPkg.userId, sElapsedRealtimeClock.millis());
+                    mPkg.userId, nowElapsed);
+            final long tempAllowlistGracePeriodEndElapsed = mTempAllowlistGraceCache.get(mUid);
+            final boolean hasTempAllowlistExemption = !mRegularJobTimer
+                    && (mTempAllowlistCache.get(mUid)
+                    || nowElapsed < tempAllowlistGracePeriodEndElapsed);
             return (standbyBucket == RESTRICTED_INDEX || !mChargeTracker.isCharging())
-                    && !mForegroundUids.get(mUid);
+                    && !mForegroundUids.get(mUid) && !hasTempAllowlistExemption;
         }
 
         void onStateChangedLocked(long nowElapsed, boolean isQuotaFree) {
@@ -2265,6 +2292,38 @@
         }
     }
 
+    final class TempAllowlistTracker implements PowerAllowlistInternal.TempAllowlistChangeListener {
+
+        @Override
+        public void onAppAdded(int uid) {
+            final long nowElapsed = sElapsedRealtimeClock.millis();
+            mTempAllowlistCache.put(uid, true);
+            final ArraySet<String> packages = getPackagesForUid(uid);
+            if (packages != null) {
+                final int userId = UserHandle.getUserId(uid);
+                for (int i = packages.size() - 1; i >= 0; --i) {
+                    Timer t = mEJPkgTimers.get(userId, packages.valueAt(i));
+                    if (t != null) {
+                        t.onStateChangedLocked(nowElapsed, true);
+                    }
+                }
+                if (maybeUpdateConstraintForUidLocked(uid)) {
+                    mStateChangedListener.onControllerStateChanged();
+                }
+            }
+        }
+
+        @Override
+        public void onAppRemoved(int uid) {
+            final long nowElapsed = sElapsedRealtimeClock.millis();
+            final long endElapsed = nowElapsed + mEJTempAllowlistGracePeriodMs;
+            mTempAllowlistCache.delete(uid);
+            mTempAllowlistGraceCache.put(uid, endElapsed);
+            Message msg = mHandler.obtainMessage(MSG_END_GRACE_PERIOD, uid, 0);
+            mHandler.sendMessageDelayed(msg, mEJTempAllowlistGracePeriodMs);
+        }
+    }
+
     private final class DeleteTimingSessionsFunctor implements Consumer<List<TimingSession>> {
         private final Predicate<TimingSession> mTooOld = new Predicate<TimingSession>() {
             public boolean test(TimingSession ts) {
@@ -2291,6 +2350,26 @@
         // getRemainingEJExecutionTimeLocked().
     }
 
+    @Nullable
+    private ArraySet<String> getPackagesForUid(final int uid) {
+        ArraySet<String> packages = mUidToPackageCache.get(uid);
+        if (packages == null) {
+            try {
+                String[] pkgs = AppGlobals.getPackageManager()
+                        .getPackagesForUid(uid);
+                if (pkgs != null) {
+                    for (String pkg : pkgs) {
+                        mUidToPackageCache.add(uid, pkg);
+                    }
+                    packages = mUidToPackageCache.get(uid);
+                }
+            } catch (RemoteException e) {
+                // Shouldn't happen.
+            }
+        }
+        return packages;
+    }
+
     private class QcHandler extends Handler {
         private boolean mIsProcessing;
 
@@ -2396,21 +2475,7 @@
                             // Update Timers first.
                             if (mPkgTimers.indexOfKey(userId) >= 0
                                     || mEJPkgTimers.indexOfKey(userId) >= 0) {
-                                ArraySet<String> packages = mUidToPackageCache.get(uid);
-                                if (packages == null) {
-                                    try {
-                                        String[] pkgs = AppGlobals.getPackageManager()
-                                                .getPackagesForUid(uid);
-                                        if (pkgs != null) {
-                                            for (String pkg : pkgs) {
-                                                mUidToPackageCache.add(uid, pkg);
-                                            }
-                                            packages = mUidToPackageCache.get(uid);
-                                        }
-                                    } catch (RemoteException e) {
-                                        Slog.wtf(TAG, "Failed to get package list", e);
-                                    }
-                                }
+                                final ArraySet<String> packages = getPackagesForUid(uid);
                                 if (packages != null) {
                                     for (int i = packages.size() - 1; i >= 0; --i) {
                                         Timer t = mEJPkgTimers.get(userId, packages.valueAt(i));
@@ -2466,6 +2531,37 @@
 
                         break;
                     }
+                    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 (DEBUG) {
+                                    Slog.d(TAG, uid + " is still allowed");
+                                }
+                                break;
+                            }
+                            if (DEBUG) {
+                                Slog.d(TAG, uid + " is now out of grace period");
+                            }
+                            final ArraySet<String> packages = getPackagesForUid(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) {
+                                        t.onStateChangedLocked(nowElapsed, false);
+                                    }
+                                }
+                                if (maybeUpdateConstraintForUidLocked(uid)) {
+                                    mStateChangedListener.onControllerStateChanged();
+                                }
+                            }
+                        }
+
+                        break;
+                    }
                 }
             }
 
@@ -2784,6 +2880,9 @@
         @VisibleForTesting
         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";
 
         private static final long DEFAULT_ALLOWED_TIME_PER_PERIOD_MS =
                 10 * 60 * 1000L; // 10 minutes
@@ -2836,6 +2935,7 @@
         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;
 
         /** 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;
@@ -3063,6 +3163,12 @@
          */
         public long EJ_REWARD_NOTIFICATION_SEEN_MS = DEFAULT_EJ_REWARD_NOTIFICATION_SEEN_MS;
 
+        /**
+         * 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 void processConstantLocked(@NonNull DeviceConfig.Properties properties,
                 @NonNull String key) {
             switch (key) {
@@ -3245,22 +3351,25 @@
                             properties.getLong(key, DEFAULT_EJ_REWARD_INTERACTION_MS);
                     // Limit interaction reward to be in the range [5 seconds, 15 minutes] per
                     // event.
-                    long newInteractionReward = Math.min(15 * MINUTE_IN_MILLIS,
+                    mEJRewardInteractionMs = Math.min(15 * MINUTE_IN_MILLIS,
                             Math.max(5 * SECOND_IN_MILLIS, EJ_REWARD_INTERACTION_MS));
-                    if (mEJRewardInteractionMs != newInteractionReward) {
-                        mEJRewardInteractionMs = newInteractionReward;
-                    }
                     break;
                 case KEY_EJ_REWARD_NOTIFICATION_SEEN_MS:
                     // We don't need to re-evaluate execution stats or constraint status for this.
                     EJ_REWARD_NOTIFICATION_SEEN_MS =
                             properties.getLong(key, DEFAULT_EJ_REWARD_NOTIFICATION_SEEN_MS);
                     // Limit notification seen reward to be in the range [0, 5] minutes per event.
-                    long newNotiSeenReward = Math.min(5 * MINUTE_IN_MILLIS,
+                    mEJRewardNotificationSeenMs = Math.min(5 * MINUTE_IN_MILLIS,
                             Math.max(0, EJ_REWARD_NOTIFICATION_SEEN_MS));
-                    if (mEJRewardNotificationSeenMs != newNotiSeenReward) {
-                        mEJRewardNotificationSeenMs = newNotiSeenReward;
-                    }
+                    break;
+                case KEY_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_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);
+                    // 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));
+                    break;
             }
         }
 
@@ -3522,6 +3631,8 @@
             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.decreaseIndent();
         }
@@ -3668,6 +3779,10 @@
         return mEJRewardTopAppMs;
     }
 
+    @VisibleForTesting
+    long getEJTempAllowlistGracePeriodMs() {
+        return mEJTempAllowlistGracePeriodMs;
+    }
 
     @VisibleForTesting
     @Nullable
@@ -3757,6 +3872,12 @@
         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();
         mTrackedJobs.forEach((jobs) -> {
             for (int j = 0; j < jobs.size(); j++) {
                 final JobStatus js = jobs.valueAt(j);
diff --git a/apex/media/framework/api/current.txt b/apex/media/framework/api/current.txt
index ce3bcbe..103bb47 100644
--- a/apex/media/framework/api/current.txt
+++ b/apex/media/framework/api/current.txt
@@ -6,9 +6,11 @@
     method public int describeContents();
     method @NonNull public java.util.List<java.lang.String> getSupportedHdrTypes();
     method @NonNull public java.util.List<java.lang.String> getSupportedVideoMimeTypes();
-    method public boolean isHdrTypeSupported(@NonNull String);
+    method @NonNull public java.util.List<java.lang.String> getUnsupportedHdrTypes();
+    method @NonNull public java.util.List<java.lang.String> getUnsupportedVideoMimeTypes();
+    method public boolean isHdrTypeSupported(@NonNull String) throws android.media.ApplicationMediaCapabilities.FormatNotFoundException;
     method public boolean isSlowMotionSupported();
-    method public boolean isVideoMimeTypeSupported(@NonNull String);
+    method public boolean isVideoMimeTypeSupported(@NonNull String) throws android.media.ApplicationMediaCapabilities.FormatNotFoundException;
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.media.ApplicationMediaCapabilities> CREATOR;
   }
@@ -17,10 +19,16 @@
     ctor public ApplicationMediaCapabilities.Builder();
     method @NonNull public android.media.ApplicationMediaCapabilities.Builder addSupportedHdrType(@NonNull String);
     method @NonNull public android.media.ApplicationMediaCapabilities.Builder addSupportedVideoMimeType(@NonNull String);
+    method @NonNull public android.media.ApplicationMediaCapabilities.Builder addUnsupportedHdrType(@NonNull String);
+    method @NonNull public android.media.ApplicationMediaCapabilities.Builder addUnsupportedVideoMimeType(@NonNull String);
     method @NonNull public android.media.ApplicationMediaCapabilities build();
     method @NonNull public android.media.ApplicationMediaCapabilities.Builder setSlowMotionSupported(boolean);
   }
 
+  public static class ApplicationMediaCapabilities.FormatNotFoundException extends android.util.AndroidException {
+    ctor public ApplicationMediaCapabilities.FormatNotFoundException(@NonNull String);
+  }
+
   public class MediaController2 implements java.lang.AutoCloseable {
     method public void cancelSessionCommand(@NonNull Object);
     method public void close();
diff --git a/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java b/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java
index 36f6b94..25ccec2 100644
--- a/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java
+++ b/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java
@@ -22,6 +22,7 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.AndroidException;
 import android.util.Log;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -68,35 +69,73 @@
 public final class ApplicationMediaCapabilities implements Parcelable {
     private static final String TAG = "ApplicationMediaCapabilities";
 
+    /**
+     * This exception is thrown when a given format is not specified in the media capabilities.
+     */
+    public static class FormatNotFoundException extends AndroidException {
+        public FormatNotFoundException(@NonNull String format) {
+            super(format);
+        }
+    }
+
     /** List of supported video codec mime types. */
     // TODO: init it with avc and mpeg4 as application is assuming to support them.
     private Set<String> mSupportedVideoMimeTypes = new HashSet<>();
 
+    /** List of unsupported video codec mime types. */
+    private Set<String> mUnsupportedVideoMimeTypes = new HashSet<>();
+
     /** List of supported hdr types. */
     private Set<String> mSupportedHdrTypes = new HashSet<>();
 
+    /** List of unsupported hdr types. */
+    private Set<String> mUnsupportedHdrTypes = new HashSet<>();
+
     private boolean mIsSlowMotionSupported = false;
 
     private ApplicationMediaCapabilities(Builder b) {
         mSupportedVideoMimeTypes.addAll(b.getSupportedVideoMimeTypes());
+        mUnsupportedVideoMimeTypes.addAll(b.getUnsupportedVideoMimeTypes());
         mSupportedHdrTypes.addAll(b.getSupportedHdrTypes());
+        mUnsupportedHdrTypes.addAll(b.getUnsupportedHdrTypes());
         mIsSlowMotionSupported = b.mIsSlowMotionSupported;
     }
 
     /**
-     * Query if an video codec is supported by the application.
+     * Query if a video codec format is supported by the application.
+     * @param videoMime The mime type of the video codec format. Must be the one used in
+     * {@link MediaFormat#KEY_MIME}.
+     * @return true if application supports the video codec format, false otherwise.
+     * @throws FormatNotFoundException if the application did not specify the codec either in the
+     * supported or unsupported formats.
      */
     public boolean isVideoMimeTypeSupported(
-            @NonNull String videoMime) {
-        return mSupportedVideoMimeTypes.contains(videoMime);
+            @NonNull String videoMime) throws FormatNotFoundException {
+        if (mUnsupportedVideoMimeTypes.contains(videoMime)) {
+            return false;
+        } else if (mSupportedVideoMimeTypes.contains(videoMime)) {
+            return true;
+        } else {
+            throw new FormatNotFoundException(videoMime);
+        }
     }
 
     /**
-     * Query if a hdr type is supported by the application.
+     * Query if a HDR type is supported by the application.
+     * @param hdrType The type of the HDR format.
+     * @return true if application supports the HDR format, false otherwise.
+     * @throws FormatNotFoundException if the application did not specify the format either in the
+     * supported or unsupported formats.
      */
     public boolean isHdrTypeSupported(
-            @NonNull @MediaFeature.MediaHdrType String hdrType) {
-        return mSupportedHdrTypes.contains(hdrType);
+            @NonNull @MediaFeature.MediaHdrType String hdrType) throws FormatNotFoundException {
+        if (mUnsupportedHdrTypes.contains(hdrType)) {
+            return false;
+        } else if (mSupportedHdrTypes.contains(hdrType)) {
+            return true;
+        } else {
+            throw new FormatNotFoundException(hdrType);
+        }
     }
 
     @Override
@@ -111,11 +150,21 @@
         for (String cap : mSupportedVideoMimeTypes) {
             dest.writeString(cap);
         }
+        // Write out the unsupported video mime types.
+        dest.writeInt(mUnsupportedVideoMimeTypes.size());
+        for (String cap : mUnsupportedVideoMimeTypes) {
+            dest.writeString(cap);
+        }
         // Write out the supported hdr types.
         dest.writeInt(mSupportedHdrTypes.size());
         for (String cap : mSupportedHdrTypes) {
             dest.writeString(cap);
         }
+        // Write out the unsupported hdr types.
+        dest.writeInt(mUnsupportedHdrTypes.size());
+        for (String cap : mUnsupportedHdrTypes) {
+            dest.writeString(cap);
+        }
         // Write out the supported slow motion.
         dest.writeBoolean(mIsSlowMotionSupported);
     }
@@ -124,7 +173,9 @@
     public String toString() {
         String caps = new String(
                 "Supported Video MimeTypes: " + mSupportedVideoMimeTypes.toString());
+        caps += "Unsupported Video MimeTypes: " + mUnsupportedVideoMimeTypes.toString();
         caps += "Supported HDR types: " + mSupportedHdrTypes.toString();
+        caps += "Unsupported HDR types: " + mUnsupportedHdrTypes.toString();
         caps += "Supported slow motion: " + mIsSlowMotionSupported;
         return caps;
     }
@@ -159,9 +210,8 @@
             };
 
     /*
-     * Returns a list that contains all the video codec mime types supported by the application.
-     * The list will be empty if no codecs are supported by the application.
-     * @return List of supported video codec mime types.
+     * Query the video codec mime types supported by the application.
+     * @return List of supported video codec mime types. The list will be empty if there are none.
      */
     @NonNull
     public List<String> getSupportedVideoMimeTypes() {
@@ -169,9 +219,17 @@
     }
 
     /*
-     * Returns a list that contains all hdr types supported by the application.
-     * The list will be empty if no hdr types are supported by the application.
-     * @return List of supported hdr types.
+     * Query the video codec mime types that are not supported by the application.
+     * @return List of unsupported video codec mime types. The list will be empty if there are none.
+     */
+    @NonNull
+    public List<String> getUnsupportedVideoMimeTypes() {
+        return new ArrayList<>(mSupportedVideoMimeTypes);
+    }
+
+    /*
+     * Query all hdr types that are supported by the application.
+     * @return List of supported hdr types. The list will be empty if there are none.
      */
     @NonNull
     public List<String> getSupportedHdrTypes() {
@@ -179,6 +237,15 @@
     }
 
     /*
+     * Query all hdr types that are not supported by the application.
+     * @return List of unsupported hdr types. The list will be empty if there are none.
+     */
+    @NonNull
+    public List<String> getUnsupportedHdrTypes()  {
+        return new ArrayList<>(mUnsupportedHdrTypes);
+    }
+
+    /*
      * Whether handling of slow-motion video is supported
      */
     public boolean isSlowMotionSupported() {
@@ -213,6 +280,12 @@
         /** List of supported hdr types. */
         private Set<String> mSupportedHdrTypes = new HashSet<>();
 
+        /** List of unsupported video codec mime types. */
+        private Set<String> mUnsupportedVideoMimeTypes = new HashSet<>();
+
+        /** List of unsupported hdr types. */
+        private Set<String> mUnsupportedHdrTypes = new HashSet<>();
+
         private boolean mIsSlowMotionSupported = false;
 
         /* Map to save the format read from the xml. */
@@ -299,26 +372,50 @@
                     case "HEVC":
                         if (isSupported) {
                             mSupportedVideoMimeTypes.add(MediaFormat.MIMETYPE_VIDEO_HEVC);
+                        } else {
+                            mUnsupportedVideoMimeTypes.add(MediaFormat.MIMETYPE_VIDEO_HEVC);
+                        }
+                        break;
+                    case "VP9":
+                        if (isSupported) {
+                            mSupportedVideoMimeTypes.add(MediaFormat.MIMETYPE_VIDEO_VP9);
+                        } else {
+                            mUnsupportedVideoMimeTypes.add(MediaFormat.MIMETYPE_VIDEO_VP9);
+                        }
+                        break;
+                    case "AV1":
+                        if (isSupported) {
+                            mSupportedVideoMimeTypes.add(MediaFormat.MIMETYPE_VIDEO_AV1);
+                        } else {
+                            mUnsupportedVideoMimeTypes.add(MediaFormat.MIMETYPE_VIDEO_AV1);
                         }
                         break;
                     case "HDR10":
                         if (isSupported) {
                             mSupportedHdrTypes.add(MediaFeature.HdrType.HDR10);
+                        } else {
+                            mUnsupportedHdrTypes.add(MediaFeature.HdrType.HDR10);
                         }
                         break;
                     case "HDR10Plus":
                         if (isSupported) {
                             mSupportedHdrTypes.add(MediaFeature.HdrType.HDR10_PLUS);
+                        } else {
+                            mUnsupportedHdrTypes.add(MediaFeature.HdrType.HDR10_PLUS);
                         }
                         break;
                     case "Dolby-Vision":
                         if (isSupported) {
                             mSupportedHdrTypes.add(MediaFeature.HdrType.DOLBY_VISION);
+                        } else {
+                            mUnsupportedHdrTypes.add(MediaFeature.HdrType.DOLBY_VISION);
                         }
                         break;
                     case "HLG":
                         if (isSupported) {
                             mSupportedHdrTypes.add(MediaFeature.HdrType.HLG);
+                        } else {
+                            mUnsupportedHdrTypes.add(MediaFeature.HdrType.HLG);
                         }
                         break;
                     case "SlowMotion":
@@ -348,8 +445,11 @@
         @NonNull
         public ApplicationMediaCapabilities build() {
             Log.d(TAG,
-                    "Building ApplicationMediaCapabilities with: " + mSupportedHdrTypes.toString()
-                            + " " + mSupportedVideoMimeTypes.toString() + " "
+                    "Building ApplicationMediaCapabilities with: (Supported HDR: "
+                            + mSupportedHdrTypes.toString() + " Unsupported HDR: "
+                            + mUnsupportedHdrTypes.toString() + ") (Supported Codec: "
+                            + " " + mSupportedVideoMimeTypes.toString() + " Unsupported Codec:"
+                            + mUnsupportedVideoMimeTypes.toString() + ") "
                             + mIsSlowMotionSupported);
 
             // If hdr is supported, application must also support hevc.
@@ -365,8 +465,7 @@
          *
          * @param codecMime Supported codec mime types. Must be one of the mime type defined
          *                  in {@link MediaFormat}.
-         * @throws UnsupportedOperationException if the codec mime type is not supported.
-         * @throws IllegalArgumentException      if mime type is not valid.
+         * @throws IllegalArgumentException if mime type is not valid.
          */
         @NonNull
         public Builder addSupportedVideoMimeType(
@@ -379,16 +478,49 @@
             return new ArrayList<>(mSupportedVideoMimeTypes);
         }
 
+        private boolean isValidVideoCodecMimeType(@NonNull String codecMime) {
+            if (!codecMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)
+                    && !codecMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9)
+                    && !codecMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AV1)) {
+                return false;
+            }
+            return true;
+        }
+
+        /**
+         * Adds an unsupported video codec mime type.
+         *
+         * @param codecMime Unsupported codec mime type. Must be one of the mime type defined
+         *                  in {@link MediaFormat}.
+         * @throws IllegalArgumentException if mime type is not valid.
+         */
+        @NonNull
+        public Builder addUnsupportedVideoMimeType(
+                @NonNull String codecMime) {
+            if (!isValidVideoCodecMimeType(codecMime)) {
+                throw new IllegalArgumentException("Invalid codec mime type: " + codecMime);
+            }
+            mUnsupportedVideoMimeTypes.add(codecMime);
+            return this;
+        }
+
+        private List<String> getUnsupportedVideoMimeTypes() {
+            return new ArrayList<>(mUnsupportedVideoMimeTypes);
+        }
+
         /**
          * Adds a supported hdr type.
          *
-         * @param hdrType Supported hdr types. Must be one of the String defined in
+         * @param hdrType Supported hdr type. Must be one of the String defined in
          *                {@link MediaFeature.HdrType}.
          * @throws IllegalArgumentException if hdrType is not valid.
          */
         @NonNull
         public Builder addSupportedHdrType(
                 @NonNull @MediaFeature.MediaHdrType String hdrType) {
+            if (!isValidVideoCodecHdrType(hdrType)) {
+                throw new IllegalArgumentException("Invalid hdr type: " + hdrType);
+            }
             mSupportedHdrTypes.add(hdrType);
             return this;
         }
@@ -397,6 +529,37 @@
             return new ArrayList<>(mSupportedHdrTypes);
         }
 
+        private boolean isValidVideoCodecHdrType(@NonNull String hdrType) {
+            if (!hdrType.equals(MediaFeature.HdrType.DOLBY_VISION)
+                    && !hdrType.equals(MediaFeature.HdrType.HDR10)
+                    && !hdrType.equals(MediaFeature.HdrType.HDR10_PLUS)
+                    && !hdrType.equals(MediaFeature.HdrType.HLG)) {
+                return false;
+            }
+            return true;
+        }
+
+        /**
+         * Adds an unsupported hdr type.
+         *
+         * @param hdrType Unsupported hdr type. Must be one of the String defined in
+         *                {@link MediaFeature.HdrType}.
+         * @throws IllegalArgumentException if hdrType is not valid.
+         */
+        @NonNull
+        public Builder addUnsupportedHdrType(
+                @NonNull @MediaFeature.MediaHdrType String hdrType) {
+            if (!isValidVideoCodecHdrType(hdrType)) {
+                throw new IllegalArgumentException("Invalid hdr type: " + hdrType);
+            }
+            mUnsupportedHdrTypes.add(hdrType);
+            return this;
+        }
+
+        private List<String> getUnsupportedHdrTypes() {
+            return new ArrayList<>(mUnsupportedHdrTypes);
+        }
+
         /**
          * Sets whether slow-motion video is supported.
          * If an application indicates support for slow-motion, it is application's responsibility
diff --git a/apex/media/framework/java/android/media/MediaTranscodeManager.java b/apex/media/framework/java/android/media/MediaTranscodeManager.java
index 3d706e4..55c4629 100644
--- a/apex/media/framework/java/android/media/MediaTranscodeManager.java
+++ b/apex/media/framework/java/android/media/MediaTranscodeManager.java
@@ -980,8 +980,15 @@
                     throw new UnsupportedOperationException(
                             "Source video format hint must be set!");
                 }
-                boolean supportHevc = mClientCaps.isVideoMimeTypeSupported(
-                        MediaFormat.MIMETYPE_VIDEO_HEVC);
+
+                boolean supportHevc = false;
+                try {
+                    supportHevc = mClientCaps.isVideoMimeTypeSupported(
+                            MediaFormat.MIMETYPE_VIDEO_HEVC);
+                } catch (ApplicationMediaCapabilities.FormatNotFoundException ex) {
+                    // Set to false if application did not specify.
+                    supportHevc = false;
+                }
                 if (!supportHevc && MediaFormat.MIMETYPE_VIDEO_HEVC.equals(
                         mSrcVideoFormatHint.getString(MediaFormat.KEY_MIME))) {
                     return true;
@@ -1016,13 +1023,11 @@
                             "Source Width and height must be larger than 0");
                 }
 
-                // TODO(hkuang): Remove the hardcoded frameRate after b/176940364 is fixed.
-                float frameRate = (float) 30.0;
-                /*mSrcVideoFormatHint.getFloat(MediaFormat.KEY_FRAME_RATE, frameRate);
+                float frameRate = mSrcVideoFormatHint.getFloat(MediaFormat.KEY_FRAME_RATE);
                 if (frameRate <= 0) {
                     throw new IllegalArgumentException(
                             "frameRate must be larger than 0");
-                }*/
+                }
 
                 int bitrate = getAVCBitrate(width, height, frameRate);
                 videoTrackFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java
index ef1e413..9088db8 100644
--- a/cmds/sm/src/com/android/commands/sm/Sm.java
+++ b/cmds/sm/src/com/android/commands/sm/Sm.java
@@ -105,6 +105,8 @@
             runStartCheckpoint();
         } else if ("supports-checkpoint".equals(op)) {
             runSupportsCheckpoint();
+        } else if ("unmount-app-data-dirs".equals(op)) {
+            runDisableAppDataIsolation();
         } else {
             throw new IllegalArgumentException();
         }
@@ -251,6 +253,13 @@
         System.out.println(result.get());
     }
 
+    public void runDisableAppDataIsolation() throws RemoteException {
+        final String pkgName = nextArg();
+        final int pid = Integer.parseInt(nextArg());
+        final int userId = Integer.parseInt(nextArg());
+        mSm.disableAppDataIsolation(pkgName, pid, userId);
+    }
+
     public void runForget() throws RemoteException {
         final String fsUuid = nextArg();
         if ("all".equals(fsUuid)) {
@@ -347,6 +356,8 @@
         System.err.println("");
         System.err.println("       sm supports-checkpoint");
         System.err.println("");
+        System.err.println("       sm unmount-app-data-dirs PACKAGE_NAME PID USER_ID");
+        System.err.println("");
         return 1;
     }
 }
diff --git a/core/api/current.txt b/core/api/current.txt
index bfa69dc..ba49b67 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -6760,7 +6760,7 @@
     method public android.content.Intent getCropAndSetWallpaperIntent(android.net.Uri);
     method public int getDesiredMinimumHeight();
     method public int getDesiredMinimumWidth();
-    method public android.graphics.drawable.Drawable getDrawable();
+    method @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) public android.graphics.drawable.Drawable getDrawable();
     method @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) public android.graphics.drawable.Drawable getFastDrawable();
     method public static android.app.WallpaperManager getInstance(android.content.Context);
     method @Nullable public android.app.WallpaperColors getWallpaperColors(int);
@@ -8163,6 +8163,7 @@
     method public long getAppBytes();
     method public long getCacheBytes();
     method public long getDataBytes();
+    method public long getExternalCacheBytes();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.usage.StorageStats> CREATOR;
   }
@@ -10350,6 +10351,7 @@
     field public static final String BIOMETRIC_SERVICE = "biometric";
     field public static final String BLOB_STORE_SERVICE = "blob_store";
     field public static final String BLUETOOTH_SERVICE = "bluetooth";
+    field public static final String BUGREPORT_SERVICE = "bugreport";
     field public static final String CAMERA_SERVICE = "camera";
     field public static final String CAPTIONING_SERVICE = "captioning";
     field public static final String CARRIER_CONFIG_SERVICE = "carrier_config";
@@ -10837,6 +10839,8 @@
     field public static final String ACTION_POWER_DISCONNECTED = "android.intent.action.ACTION_POWER_DISCONNECTED";
     field public static final String ACTION_POWER_USAGE_SUMMARY = "android.intent.action.POWER_USAGE_SUMMARY";
     field public static final String ACTION_PROCESS_TEXT = "android.intent.action.PROCESS_TEXT";
+    field public static final String ACTION_PROFILE_ACCESSIBLE = "android.intent.action.PROFILE_ACCESSIBLE";
+    field public static final String ACTION_PROFILE_INACCESSIBLE = "android.intent.action.PROFILE_INACCESSIBLE";
     field public static final String ACTION_PROVIDER_CHANGED = "android.intent.action.PROVIDER_CHANGED";
     field public static final String ACTION_QUICK_CLOCK = "android.intent.action.QUICK_CLOCK";
     field public static final String ACTION_QUICK_VIEW = "android.intent.action.QUICK_VIEW";
@@ -12049,7 +12053,6 @@
 
   public static class PackageInstaller.Session implements java.io.Closeable {
     method public void abandon();
-    method @Deprecated public void addChecksums(@NonNull String, @NonNull java.util.List<android.content.pm.Checksum>) throws java.io.IOException;
     method public void addChildSessionId(int);
     method public void close();
     method public void commit(@NonNull android.content.IntentSender);
@@ -12063,6 +12066,7 @@
     method @NonNull public java.io.OutputStream openWrite(@NonNull String, long, long) throws java.io.IOException;
     method public void removeChildSessionId(int);
     method public void removeSplit(@NonNull String) throws java.io.IOException;
+    method @Deprecated public void setChecksums(@NonNull String, @NonNull java.util.List<android.content.pm.Checksum>, @Nullable byte[]) throws java.io.IOException;
     method public void setStagingProgress(float);
     method public void transfer(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
   }
@@ -15543,7 +15547,6 @@
     ctor public Point(int, int);
     ctor public Point(@NonNull android.graphics.Point);
     method public int describeContents();
-    method public final void dump(@NonNull java.io.PrintWriter);
     method public final boolean equals(int, int);
     method public final void negate();
     method public final void offset(int, int);
@@ -30082,6 +30085,24 @@
     method public boolean unlinkToDeath(@NonNull android.os.IBinder.DeathRecipient, int);
   }
 
+  public final class BugreportManager {
+    method public void cancelBugreport();
+    method public void startConnectivityBugreport(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback);
+  }
+
+  public abstract static class BugreportManager.BugreportCallback {
+    ctor public BugreportManager.BugreportCallback();
+    method public void onEarlyReportFinished();
+    method public void onError(int);
+    method public void onFinished();
+    method public void onProgress(@FloatRange(from=0.0f, to=100.0f) float);
+    field public static final int BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS = 5; // 0x5
+    field public static final int BUGREPORT_ERROR_INVALID_INPUT = 1; // 0x1
+    field public static final int BUGREPORT_ERROR_RUNTIME = 2; // 0x2
+    field public static final int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT = 4; // 0x4
+    field public static final int BUGREPORT_ERROR_USER_DENIED_CONSENT = 3; // 0x3
+  }
+
   public class Build {
     ctor public Build();
     method @NonNull public static java.util.List<android.os.Build.Partition> getFingerprintedPartitions();
@@ -34471,6 +34492,7 @@
     field public static final String ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS";
     field public static final String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
     field public static final String ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION = "android.settings.MANAGE_ALL_FILES_ACCESS_PERMISSION";
+    field public static final String ACTION_MANAGE_ALL_SUBSCRIPTIONS_SETTINGS = "android.settings.MANAGE_ALL_SUBSCRIPTIONS_SETTINGS";
     field public static final String ACTION_MANAGE_APPLICATIONS_SETTINGS = "android.settings.MANAGE_APPLICATIONS_SETTINGS";
     field public static final String ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION = "android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION";
     field public static final String ACTION_MANAGE_DEFAULT_APPS_SETTINGS = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS";
@@ -39764,6 +39786,7 @@
     field public static final int BAND_25 = 25; // 0x19
     field public static final int BAND_257 = 257; // 0x101
     field public static final int BAND_258 = 258; // 0x102
+    field public static final int BAND_26 = 26; // 0x1a
     field public static final int BAND_260 = 260; // 0x104
     field public static final int BAND_261 = 261; // 0x105
     field public static final int BAND_28 = 28; // 0x1c
@@ -39775,10 +39798,12 @@
     field public static final int BAND_39 = 39; // 0x27
     field public static final int BAND_40 = 40; // 0x28
     field public static final int BAND_41 = 41; // 0x29
+    field public static final int BAND_46 = 46; // 0x2e
     field public static final int BAND_48 = 48; // 0x30
     field public static final int BAND_5 = 5; // 0x5
     field public static final int BAND_50 = 50; // 0x32
     field public static final int BAND_51 = 51; // 0x33
+    field public static final int BAND_53 = 53; // 0x35
     field public static final int BAND_65 = 65; // 0x41
     field public static final int BAND_66 = 66; // 0x42
     field public static final int BAND_7 = 7; // 0x7
@@ -39804,6 +39829,7 @@
     field public static final int BAND_93 = 93; // 0x5d
     field public static final int BAND_94 = 94; // 0x5e
     field public static final int BAND_95 = 95; // 0x5f
+    field public static final int BAND_96 = 96; // 0x60
   }
 
   public static final class AccessNetworkConstants.UtranBand {
@@ -41315,17 +41341,27 @@
 
   public final class PhysicalChannelConfig implements android.os.Parcelable {
     method public int describeContents();
-    method public int getCellBandwidthDownlink();
-    method public int getChannelNumber();
+    method @IntRange(from=1, to=261) public int getBand();
+    method @IntRange(from=1) public int getCellBandwidthDownlinkKhz();
+    method @IntRange(from=1) public int getCellBandwidthUplinkKhz();
+    method @Deprecated public int getChannelNumber();
     method public int getConnectionStatus();
+    method @IntRange(from=0) public int getDownlinkChannelNumber();
+    method @IntRange(from=0) public int getDownlinkFrequencyKhz();
     method public int getNetworkType();
     method @IntRange(from=0, to=1007) public int getPhysicalCellId();
+    method @IntRange(from=0) public int getUplinkChannelNumber();
+    method @IntRange(from=0) public int getUplinkFrequencyKhz();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int BAND_UNKNOWN = 0; // 0x0
+    field public static final int CELL_BANDWIDTH_UNKNOWN = 0; // 0x0
     field public static final int CHANNEL_NUMBER_UNKNOWN = -1; // 0xffffffff
     field public static final int CONNECTION_PRIMARY_SERVING = 1; // 0x1
     field public static final int CONNECTION_SECONDARY_SERVING = 2; // 0x2
     field public static final int CONNECTION_UNKNOWN = -1; // 0xffffffff
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PhysicalChannelConfig> CREATOR;
+    field public static final int FREQUENCY_UNKNOWN = -1; // 0xffffffff
+    field public static final int PHYSICAL_CELL_ID_MAXIMUM_VALUE = 1007; // 0x3ef
     field public static final int PHYSICAL_CELL_ID_UNKNOWN = -1; // 0xffffffff
   }
 
@@ -41408,6 +41444,49 @@
     field public static final int INVALID = 2147483647; // 0x7fffffff
   }
 
+  public final class SignalStrengthUpdateRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public java.util.Collection<android.telephony.SignalThresholdInfo> getSignalThresholdInfos();
+    method public boolean isReportingRequestedWhileIdle();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.SignalStrengthUpdateRequest> CREATOR;
+  }
+
+  public static final class SignalStrengthUpdateRequest.Builder {
+    ctor public SignalStrengthUpdateRequest.Builder();
+    method @NonNull public android.telephony.SignalStrengthUpdateRequest build();
+    method @NonNull public android.telephony.SignalStrengthUpdateRequest.Builder setReportingRequestedWhileIdle(boolean);
+    method @NonNull public android.telephony.SignalStrengthUpdateRequest.Builder setSignalThresholdInfos(@NonNull java.util.Collection<android.telephony.SignalThresholdInfo>);
+  }
+
+  public final class SignalThresholdInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public static int getMaximumNumberOfThresholdsAllowed();
+    method public static int getMinimumNumberOfThresholdsAllowed();
+    method public int getRadioAccessNetworkType();
+    method public int getSignalMeasurementType();
+    method @NonNull public int[] getThresholds();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.SignalThresholdInfo> CREATOR;
+    field public static final int SIGNAL_MEASUREMENT_TYPE_RSCP = 2; // 0x2
+    field public static final int SIGNAL_MEASUREMENT_TYPE_RSRP = 3; // 0x3
+    field public static final int SIGNAL_MEASUREMENT_TYPE_RSRQ = 4; // 0x4
+    field public static final int SIGNAL_MEASUREMENT_TYPE_RSSI = 1; // 0x1
+    field public static final int SIGNAL_MEASUREMENT_TYPE_RSSNR = 5; // 0x5
+    field public static final int SIGNAL_MEASUREMENT_TYPE_SSRSRP = 6; // 0x6
+    field public static final int SIGNAL_MEASUREMENT_TYPE_SSRSRQ = 7; // 0x7
+    field public static final int SIGNAL_MEASUREMENT_TYPE_SSSINR = 8; // 0x8
+    field public static final int SIGNAL_MEASUREMENT_TYPE_UNKNOWN = 0; // 0x0
+  }
+
+  public static final class SignalThresholdInfo.Builder {
+    ctor public SignalThresholdInfo.Builder();
+    method @NonNull public android.telephony.SignalThresholdInfo build();
+    method @NonNull public android.telephony.SignalThresholdInfo.Builder setRadioAccessNetworkType(int);
+    method @NonNull public android.telephony.SignalThresholdInfo.Builder setSignalMeasurementType(int);
+    method @NonNull public android.telephony.SignalThresholdInfo.Builder setThresholds(@NonNull int[]);
+  }
+
   public final class SmsManager {
     method public String createAppSpecificSmsToken(android.app.PendingIntent);
     method @Nullable public String createAppSpecificSmsTokenWithPackageInfo(@Nullable String, @NonNull android.app.PendingIntent);
@@ -49319,8 +49398,9 @@
     method public void show(int);
     field public static final int APPEARANCE_LIGHT_NAVIGATION_BARS = 16; // 0x10
     field public static final int APPEARANCE_LIGHT_STATUS_BARS = 8; // 0x8
-    field public static final int BEHAVIOR_SHOW_BARS_BY_SWIPE = 1; // 0x1
-    field public static final int BEHAVIOR_SHOW_BARS_BY_TOUCH = 0; // 0x0
+    field public static final int BEHAVIOR_DEFAULT = 1; // 0x1
+    field @Deprecated public static final int BEHAVIOR_SHOW_BARS_BY_SWIPE = 1; // 0x1
+    field @Deprecated public static final int BEHAVIOR_SHOW_BARS_BY_TOUCH = 0; // 0x0
     field public static final int BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE = 2; // 0x2
   }
 
@@ -51683,6 +51763,10 @@
   }
 
   public final class TextServicesManager {
+    method @Nullable public android.view.textservice.SpellCheckerInfo getCurrentSpellChecker();
+    method @Nullable public android.view.textservice.SpellCheckerSubtype getCurrentSpellCheckerSubtype(boolean);
+    method @Nullable public java.util.List<android.view.textservice.SpellCheckerInfo> getEnabledSpellCheckersList();
+    method public boolean isSpellCheckerEnabled();
     method public android.view.textservice.SpellCheckerSession newSpellCheckerSession(android.os.Bundle, java.util.Locale, android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener, boolean);
   }
 
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 2ebcb19..d91ea2c 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -137,6 +137,7 @@
     field public static final String MANAGE_SOUND_TRIGGER = "android.permission.MANAGE_SOUND_TRIGGER";
     field public static final String MANAGE_SUBSCRIPTION_PLANS = "android.permission.MANAGE_SUBSCRIPTION_PLANS";
     field public static final String MANAGE_TIME_AND_ZONE_DETECTION = "android.permission.MANAGE_TIME_AND_ZONE_DETECTION";
+    field public static final String MANAGE_UI_TRANSLATION = "android.permission.MANAGE_UI_TRANSLATION";
     field public static final String MANAGE_USB = "android.permission.MANAGE_USB";
     field public static final String MANAGE_USERS = "android.permission.MANAGE_USERS";
     field public static final String MANAGE_USER_OEM_UNLOCK_STATE = "android.permission.MANAGE_USER_OEM_UNLOCK_STATE";
@@ -369,6 +370,8 @@
     method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener);
     method public void setDeviceLocales(@NonNull android.os.LocaleList);
     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);
   }
 
@@ -893,6 +896,8 @@
     field public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI";
     field public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL";
     field public static final String EXTRA_PROVISIONING_ORGANIZATION_NAME = "android.app.extra.PROVISIONING_ORGANIZATION_NAME";
+    field public static final String EXTRA_PROVISIONING_RETURN_BEFORE_POLICY_COMPLIANCE = "android.app.extra.PROVISIONING_RETURN_BEFORE_POLICY_COMPLIANCE";
+    field public static final String EXTRA_PROVISIONING_SKIP_OWNERSHIP_DISCLAIMER = "android.app.extra.PROVISIONING_SKIP_OWNERSHIP_DISCLAIMER";
     field public static final String EXTRA_PROVISIONING_SUPPORTED_MODES = "android.app.extra.PROVISIONING_SUPPORTED_MODES";
     field public static final String EXTRA_PROVISIONING_SUPPORT_URL = "android.app.extra.PROVISIONING_SUPPORT_URL";
     field public static final String EXTRA_PROVISIONING_TRIGGER = "android.app.extra.PROVISIONING_TRIGGER";
@@ -1922,7 +1927,6 @@
     field public static final String BATTERY_STATS_SERVICE = "batterystats";
     field public static final int BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS = 1048576; // 0x100000
     field public static final int BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND = 262144; // 0x40000
-    field public static final String BUGREPORT_SERVICE = "bugreport";
     field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
     field public static final String CONTEXTHUB_SERVICE = "contexthub";
     field public static final String ETHERNET_SERVICE = "ethernet";
@@ -1944,6 +1948,7 @@
     field public static final String SYSTEM_UPDATE_SERVICE = "system_update";
     field public static final String TETHERING_SERVICE = "tethering";
     field public static final String TRANSLATION_MANAGER_SERVICE = "transformer";
+    field public static final String UI_TRANSLATION_SERVICE = "ui_translation";
     field public static final String VR_SERVICE = "vrmanager";
     field public static final String WIFI_NL80211_SERVICE = "wifinl80211";
     field @Deprecated public static final String WIFI_RTT_SERVICE = "rttmanager";
@@ -5350,9 +5355,9 @@
     method public int disconnectFrontendToCiCam(int);
     method public int getAvSyncHwId(@NonNull android.media.tv.tuner.filter.Filter);
     method public long getAvSyncTime(int);
+    method @Nullable public java.util.List<android.media.tv.tuner.frontend.FrontendInfo> getAvailableFrontendInfos();
     method @Nullable public android.media.tv.tuner.DemuxCapabilities getDemuxCapabilities();
     method @Nullable public android.media.tv.tuner.frontend.FrontendInfo getFrontendInfo();
-    method @Nullable public java.util.List<android.media.tv.tuner.frontend.FrontendInfo> getFrontendInfoList();
     method @Nullable public android.media.tv.tuner.frontend.FrontendStatus getFrontendStatus(@NonNull int[]);
     method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_DESCRAMBLER) public android.media.tv.tuner.Descrambler openDescrambler();
     method @Nullable public android.media.tv.tuner.dvr.DvrPlayback openDvrPlayback(long, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.dvr.OnPlaybackStatusChangedListener);
@@ -7852,24 +7857,10 @@
   }
 
   public final class BugreportManager {
-    method @RequiresPermission(android.Manifest.permission.DUMP) public void cancelBugreport();
     method @RequiresPermission(android.Manifest.permission.DUMP) public void requestBugreport(@NonNull android.os.BugreportParams, @Nullable CharSequence, @Nullable CharSequence);
     method @RequiresPermission(android.Manifest.permission.DUMP) public void startBugreport(@NonNull android.os.ParcelFileDescriptor, @Nullable android.os.ParcelFileDescriptor, @NonNull android.os.BugreportParams, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback);
   }
 
-  public abstract static class BugreportManager.BugreportCallback {
-    ctor public BugreportManager.BugreportCallback();
-    method public void onEarlyReportFinished();
-    method public void onError(int);
-    method public void onFinished();
-    method public void onProgress(@FloatRange(from=0.0f, to=100.0f) float);
-    field public static final int BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS = 5; // 0x5
-    field public static final int BUGREPORT_ERROR_INVALID_INPUT = 1; // 0x1
-    field public static final int BUGREPORT_ERROR_RUNTIME = 2; // 0x2
-    field public static final int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT = 4; // 0x4
-    field public static final int BUGREPORT_ERROR_USER_DENIED_CONSENT = 3; // 0x3
-  }
-
   public final class BugreportParams {
     ctor public BugreportParams(int);
     method public int getMode();
@@ -10242,6 +10233,7 @@
     method @Nullable public android.telecom.PhoneAccountHandle getPhoneAccountHandle();
     method @Nullable public final String getTelecomCallId();
     method @Deprecated public void onAudioStateChanged(android.telecom.AudioState);
+    method @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public void onCallFilteringCompleted(boolean, boolean);
     method public final void resetConnectionTime();
     method public void setCallDirection(int);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public final void setConnectTimeMillis(@IntRange(from=0) long);
@@ -10418,6 +10410,7 @@
   }
 
   public final class RemoteConnection {
+    method @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public void onCallFilteringCompleted(boolean, boolean);
     method @Deprecated public void setAudioState(android.telecom.AudioState);
   }
 
@@ -10601,6 +10594,7 @@
   public static final class CarrierConfigManager.Wifi {
     field public static final String KEY_HOTSPOT_MAX_CLIENT_COUNT = "wifi.hotspot_maximum_client_count";
     field public static final String KEY_PREFIX = "wifi.";
+    field public static final String KEY_SUGGESTION_SSID_LIST_WITH_MAC_RANDOMIZATION_DISABLED = "wifi.suggestion_ssid_list_with_mac_randomization_disabled";
   }
 
   public final class CarrierRestrictionRules implements android.os.Parcelable {
@@ -13445,6 +13439,17 @@
 
 }
 
+package android.view.translation {
+
+  public final class UiTranslationManager {
+    method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void finishTranslation(int);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void pauseTranslation(int);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void resumeTranslation(int);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void startTranslation(@NonNull android.view.translation.TranslationSpec, @NonNull android.view.translation.TranslationSpec, @NonNull java.util.List<android.view.autofill.AutofillId>, int);
+  }
+
+}
+
 package android.webkit {
 
   public abstract class CookieManager {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 015ae64..9e83136 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -254,6 +254,7 @@
     method public boolean isImportanceLockedByOEM();
     method public void lockFields(int);
     method public void setDeleted(boolean);
+    method public void setDeletedTimeMs(long);
     method public void setDemoted(boolean);
     method public void setFgServiceShown(boolean);
     method public void setImportanceLockedByCriticalDeviceFunction(boolean);
@@ -385,18 +386,35 @@
     method @NonNull public static String operationToString(int);
     method @RequiresPermission("android.permission.MANAGE_DEVICE_ADMINS") public void setNextOperationSafety(int, boolean);
     field public static final String ACTION_DATA_SHARING_RESTRICTION_APPLIED = "android.app.action.DATA_SHARING_RESTRICTION_APPLIED";
+    field public static final int OPERATION_CLEAR_APPLICATION_USER_DATA = 23; // 0x17
     field public static final int OPERATION_CREATE_AND_MANAGE_USER = 5; // 0x5
+    field public static final int OPERATION_INSTALL_CA_CERT = 24; // 0x18
+    field public static final int OPERATION_INSTALL_KEY_PAIR = 25; // 0x19
+    field public static final int OPERATION_INSTALL_SYSTEM_UPDATE = 26; // 0x1a
     field public static final int OPERATION_LOCK_NOW = 1; // 0x1
     field public static final int OPERATION_LOGOUT_USER = 9; // 0x9
     field public static final int OPERATION_REBOOT = 7; // 0x7
+    field public static final int OPERATION_REMOVE_ACTIVE_ADMIN = 27; // 0x1b
+    field public static final int OPERATION_REMOVE_KEY_PAIR = 28; // 0x1c
     field public static final int OPERATION_REMOVE_USER = 6; // 0x6
+    field public static final int OPERATION_REQUEST_BUGREPORT = 29; // 0x1d
+    field public static final int OPERATION_SET_ALWAYS_ON_VPN_PACKAGE = 30; // 0x1e
     field public static final int OPERATION_SET_APPLICATION_HIDDEN = 15; // 0xf
     field public static final int OPERATION_SET_APPLICATION_RESTRICTIONS = 16; // 0x10
+    field public static final int OPERATION_SET_CAMERA_DISABLED = 31; // 0x1f
+    field public static final int OPERATION_SET_FACTORY_RESET_PROTECTION_POLICY = 32; // 0x20
+    field public static final int OPERATION_SET_GLOBAL_PRIVATE_DNS = 33; // 0x21
     field public static final int OPERATION_SET_KEEP_UNINSTALLED_PACKAGES = 17; // 0x11
     field public static final int OPERATION_SET_KEYGUARD_DISABLED = 12; // 0xc
     field public static final int OPERATION_SET_LOCK_TASK_FEATURES = 18; // 0x12
     field public static final int OPERATION_SET_LOCK_TASK_PACKAGES = 19; // 0x13
+    field public static final int OPERATION_SET_LOGOUT_ENABLED = 34; // 0x22
+    field public static final int OPERATION_SET_MASTER_VOLUME_MUTED = 35; // 0x23
+    field public static final int OPERATION_SET_OVERRIDE_APNS_ENABLED = 36; // 0x24
     field public static final int OPERATION_SET_PACKAGES_SUSPENDED = 20; // 0x14
+    field public static final int OPERATION_SET_PERMISSION_GRANT_STATE = 37; // 0x25
+    field public static final int OPERATION_SET_PERMISSION_POLICY = 38; // 0x26
+    field public static final int OPERATION_SET_RESTRICTIONS_PROVIDER = 39; // 0x27
     field public static final int OPERATION_SET_STATUS_BAR_DISABLED = 13; // 0xd
     field public static final int OPERATION_SET_SYSTEM_SETTING = 11; // 0xb
     field public static final int OPERATION_SET_SYSTEM_UPDATE_POLICY = 14; // 0xe
@@ -406,6 +424,7 @@
     field public static final int OPERATION_START_USER_IN_BACKGROUND = 3; // 0x3
     field public static final int OPERATION_STOP_USER = 4; // 0x4
     field public static final int OPERATION_SWITCH_USER = 2; // 0x2
+    field public static final int OPERATION_UNINSTALL_CA_CERT = 40; // 0x28
     field public static final int OPERATION_WIPE_DATA = 8; // 0x8
   }
 
@@ -449,13 +468,10 @@
 
 package android.app.role {
 
-  public class RoleControllerManager {
-    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void isApplicationVisibleForRole(@NonNull String, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
-    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void isRoleVisible(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
-  }
-
   public final class RoleManager {
     method @Nullable public String getSmsRoleHolder(int);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void isApplicationVisibleForRole(@NonNull String, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void isRoleVisible(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
   }
 
 }
@@ -1351,11 +1367,10 @@
 
   public static class VibrationEffect.Prebaked extends android.os.VibrationEffect implements android.os.Parcelable {
     ctor public VibrationEffect.Prebaked(android.os.Parcel);
-    ctor public VibrationEffect.Prebaked(int, boolean);
+    ctor public VibrationEffect.Prebaked(int, boolean, int);
     method public long getDuration();
     method public int getEffectStrength();
     method public int getId();
-    method public void setEffectStrength(int);
     method public boolean shouldFallback();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.os.VibrationEffect.Prebaked> CREATOR;
@@ -1609,6 +1624,11 @@
 
 package android.security {
 
+  public final class KeyChain {
+    method @RequiresPermission("android.permission.MANAGE_CREDENTIAL_MANAGEMENT_APP") public static boolean removeCredentialManagementApp(@NonNull android.content.Context);
+    method @RequiresPermission("android.permission.MANAGE_CREDENTIAL_MANAGEMENT_APP") public static boolean setCredentialManagementApp(@NonNull android.content.Context, @NonNull String, @NonNull android.security.AppUriAuthenticationPolicy);
+  }
+
   public class KeyStoreException extends java.lang.Exception {
     ctor public KeyStoreException(int, String);
     method public int getErrorCode();
@@ -2376,10 +2396,6 @@
     field public static final int SUBTYPE_ID_NONE = 0; // 0x0
   }
 
-  public final class TextServicesManager {
-    method public boolean isSpellCheckerEnabled();
-  }
-
 }
 
 package android.widget {
diff --git a/core/java/android/accessibilityservice/OWNERS b/core/java/android/accessibilityservice/OWNERS
index c6f42f7..a31cfae 100644
--- a/core/java/android/accessibilityservice/OWNERS
+++ b/core/java/android/accessibilityservice/OWNERS
@@ -1,4 +1,4 @@
 svetoslavganov@google.com
 pweaver@google.com
 rhedjao@google.com
-qasid@google.com
+ryanlwlin@google.com
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 8c62e9c..520959c 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -3883,6 +3883,52 @@
     }
 
     /**
+     * Starts a profile.
+     * To be used with non-managed profiles, managed profiles should use
+     * {@link UserManager#requestQuietModeEnabled}
+     *
+     * @param userHandle user handle of the profile.
+     * @return true if the profile has been successfully started or if the profile is already
+     * running, false if profile failed to start.
+     * @throws IllegalArgumentException if {@code userHandle} is not a profile.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.INTERACT_ACROSS_USERS_FULL})
+    public boolean startProfile(@NonNull UserHandle userHandle) {
+        try {
+            return getService().startProfile(userHandle.getIdentifier());
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Stops a running profile.
+     * To be used with non-managed profiles, managed profiles should use
+     * {@link UserManager#requestQuietModeEnabled}
+     *
+     * @param userHandle user handle of the profile.
+     * @return true if the profile has been successfully stopped or is already stopped. Otherwise
+     * the exceptions listed below are thrown.
+     * @throws IllegalArgumentException if {@code userHandle} is not a profile.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.INTERACT_ACROSS_USERS_FULL})
+    public boolean stopProfile(@NonNull UserHandle userHandle) {
+        try {
+            return getService().stopProfile(userHandle.getIdentifier());
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Updates the MCC (Mobile Country Code) and MNC (Mobile Network Code) in the
      * system configuration.
      *
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index f7f42a6..986051c 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -98,7 +98,7 @@
     public abstract void killForegroundAppsForUser(@UserIdInt int userId);
 
     /**
-     * Sets how long a {@link PendingIntent} can be temporarily whitelist to by bypass restrictions
+     * Sets how long a {@link PendingIntent} can be temporarily allowlisted to bypass restrictions
      * such as Power Save mode.
      * @param target
      * @param whitelistToken
@@ -132,9 +132,14 @@
 
     /**
      * Update information about which app IDs are on the temp whitelist.
+     * @param appids the updated list of appIds in temp allowlist.
+     * @param changingUid uid to add or remove to temp allowlist.
+     * @param adding true to add to temp allowlist, false to remove from temp allowlist.
+     * @param durationMs when adding is true, the duration to be in temp allowlist.
+     * @param type temp allowlist type defined at {@link BroadcastOptions.TempAllowListType}.
      */
-    public abstract void updateDeviceIdleTempWhitelist(int[] appids, int changingAppId,
-            boolean adding);
+    public abstract void updateDeviceIdleTempWhitelist(int[] appids, int changingUid,
+            boolean adding, long durationMs, @BroadcastOptions.TempAllowListType int type);
 
     /**
      * Get the procstate for the UID.  The return value will be between
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index f541e1a..d0d5df9 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -54,6 +54,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
+import android.window.IRemoteTransition;
 import android.window.WindowContainerToken;
 
 import java.lang.annotation.Retention;
@@ -298,6 +299,8 @@
     private static final String KEY_SPECS_FUTURE = "android:activity.specsFuture";
     private static final String KEY_REMOTE_ANIMATION_ADAPTER
             = "android:activity.remoteAnimationAdapter";
+    private static final String KEY_REMOTE_TRANSITION =
+            "android:activity.remoteTransition";
 
     /**
      * @see #setLaunchCookie
@@ -380,6 +383,7 @@
     private IAppTransitionAnimationSpecsFuture mSpecsFuture;
     private RemoteAnimationAdapter mRemoteAnimationAdapter;
     private IBinder mLaunchCookie;
+    private IRemoteTransition mRemoteTransition;
 
     /**
      * Create an ActivityOptions specifying a custom animation to run when
@@ -959,6 +963,21 @@
         return opts;
     }
 
+    /**
+     * Create an {@link ActivityOptions} instance that lets the application control the entire
+     * animation using a {@link RemoteAnimationAdapter}.
+     * @hide
+     */
+    @RequiresPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS)
+    public static ActivityOptions makeRemoteAnimation(RemoteAnimationAdapter remoteAnimationAdapter,
+            IRemoteTransition remoteTransition) {
+        final ActivityOptions opts = new ActivityOptions();
+        opts.mRemoteAnimationAdapter = remoteAnimationAdapter;
+        opts.mAnimationType = ANIM_REMOTE_ANIMATION;
+        opts.mRemoteTransition = remoteTransition;
+        return opts;
+    }
+
     /** @hide */
     public boolean getLaunchTaskBehind() {
         return mAnimationType == ANIM_LAUNCH_TASK_BEHIND;
@@ -1064,6 +1083,8 @@
         }
         mRemoteAnimationAdapter = opts.getParcelable(KEY_REMOTE_ANIMATION_ADAPTER);
         mLaunchCookie = opts.getBinder(KEY_LAUNCH_COOKIE);
+        mRemoteTransition = IRemoteTransition.Stub.asInterface(opts.getBinder(
+                KEY_REMOTE_TRANSITION));
     }
 
     /**
@@ -1223,6 +1244,11 @@
     }
 
     /** @hide */
+    public IRemoteTransition getRemoteTransition() {
+        return mRemoteTransition;
+    }
+
+    /** @hide */
     public static ActivityOptions fromBundle(Bundle bOptions) {
         return bOptions != null ? new ActivityOptions(bOptions) : null;
     }
@@ -1724,6 +1750,9 @@
         if (mLaunchCookie != null) {
             b.putBinder(KEY_LAUNCH_COOKIE, mLaunchCookie);
         }
+        if (mRemoteTransition != null) {
+            b.putBinder(KEY_REMOTE_TRANSITION, mRemoteTransition.asBinder());
+        }
         return b;
     }
 
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index a23dd35..161b731 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1645,7 +1645,7 @@
      */
     private static int[] sOpToSwitch = new int[] {
             OP_COARSE_LOCATION,                 // COARSE_LOCATION
-            OP_COARSE_LOCATION,                 // FINE_LOCATION
+            OP_FINE_LOCATION,                   // FINE_LOCATION
             OP_COARSE_LOCATION,                 // GPS
             OP_VIBRATE,                         // VIBRATE
             OP_READ_CONTACTS,                   // READ_CONTACTS
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index c1ed7b2..bac5025 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1995,8 +1995,7 @@
     }
 
     private static boolean isUiComponent(String name) {
-        return WINDOW_SERVICE.equals(name) || LAYOUT_INFLATER_SERVICE.equals(name)
-                || WALLPAPER_SERVICE.equals(name);
+        return WINDOW_SERVICE.equals(name) || LAYOUT_INFLATER_SERVICE.equals(name);
     }
 
     @Override
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index 9fdff59..f7097fa 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -470,9 +470,6 @@
                 || mSharedElementsHidden)) {
             finish();
         }
-        if (!mIsReturning && mExitNotified) {
-            mExitCallbacks = null; // don't need it anymore
-        }
     }
 
     private void finish() {
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 1b8f049..0019fd1 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -686,4 +686,22 @@
      * {@link android.content.pm.PackageManager#getHoldLockToken()}.
      */
     void holdLock(in IBinder token, in int durationMs);
+
+    /**
+     * Starts a profile.
+     * @param userId the user id of the profile.
+     * @return true if the profile has been successfully started or if the profile is already
+     * running, false if profile failed to start.
+     * @throws IllegalArgumentException if the user is not a profile.
+     */
+    boolean startProfile(int userId);
+
+    /**
+     * Stops a profile.
+     * @param userId the user id of the profile.
+     * @return true if the profile has been successfully stopped or is already stopped. Otherwise
+     * the exceptions listed below are thrown.
+     * @throws IllegalArgumentException if the user is not a profile.
+     */
+    boolean stopProfile(int userId);
 }
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index b1a8f9b..323af821 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -32,6 +32,7 @@
 import android.provider.Settings;
 import android.service.notification.NotificationListenerService;
 import android.text.TextUtils;
+import android.util.Slog;
 import android.util.TypedXmlPullParser;
 import android.util.TypedXmlSerializer;
 import android.util.proto.ProtoOutputStream;
@@ -111,6 +112,7 @@
     private static final String ATT_CONVERSATION_ID = "conv_id";
     private static final String ATT_IMP_CONVERSATION = "imp_conv";
     private static final String ATT_DEMOTE = "dem";
+    private static final String ATT_DELETED_TIME_MS = "del_time";
     private static final String DELIMITER = ",";
 
     /**
@@ -183,6 +185,7 @@
             NotificationManager.IMPORTANCE_UNSPECIFIED;
     private static final boolean DEFAULT_DELETED = false;
     private static final boolean DEFAULT_SHOW_BADGE = true;
+    private static final long DEFAULT_DELETION_TIME_MS = -1;
 
     @UnsupportedAppUsage
     private String mId;
@@ -214,6 +217,7 @@
     private String mConversationId = null;
     private boolean mDemoted = false;
     private boolean mImportantConvo = false;
+    private long mDeletedTime = DEFAULT_DELETION_TIME_MS;
 
     /**
      * Creates a notification channel.
@@ -282,6 +286,7 @@
         mConversationId = in.readString();
         mDemoted = in.readBoolean();
         mImportantConvo = in.readBoolean();
+        mDeletedTime = in.readLong();
     }
 
     @Override
@@ -341,6 +346,7 @@
         dest.writeString(mConversationId);
         dest.writeBoolean(mDemoted);
         dest.writeBoolean(mImportantConvo);
+        dest.writeLong(mDeletedTime);
     }
 
     /**
@@ -378,6 +384,14 @@
      * @hide
      */
     @TestApi
+    public void setDeletedTimeMs(long time) {
+        mDeletedTime = time;
+    }
+
+    /**
+     * @hide
+     */
+    @TestApi
     public void setImportantConversation(boolean importantConvo) {
         mImportantConvo = importantConvo;
     }
@@ -766,6 +780,13 @@
     /**
      * @hide
      */
+    public long getDeletedTimeMs() {
+        return mDeletedTime;
+    }
+
+    /**
+     * @hide
+     */
     @SystemApi
     public int getUserLockedFields() {
         return mUserLockedFields;
@@ -906,6 +927,8 @@
         enableVibration(safeBool(parser, ATT_VIBRATION_ENABLED, false));
         setShowBadge(safeBool(parser, ATT_SHOW_BADGE, false));
         setDeleted(safeBool(parser, ATT_DELETED, false));
+        setDeletedTimeMs(XmlUtils.readLongAttribute(
+                parser, ATT_DELETED_TIME_MS, DEFAULT_DELETION_TIME_MS));
         setGroup(parser.getAttributeValue(null, ATT_GROUP));
         lockFields(safeInt(parser, ATT_USER_LOCKED, 0));
         setFgServiceShown(safeBool(parser, ATT_FG_SERVICE_SHOWN, false));
@@ -1024,6 +1047,9 @@
         if (isDeleted()) {
             out.attributeBoolean(null, ATT_DELETED, isDeleted());
         }
+        if (getDeletedTimeMs() >= 0) {
+            out.attributeLong(null, ATT_DELETED_TIME_MS, getDeletedTimeMs());
+        }
         if (getGroup() != null) {
             out.attribute(null, ATT_GROUP, getGroup());
         }
@@ -1091,6 +1117,7 @@
         record.put(ATT_VIBRATION, longArrayToString(getVibrationPattern()));
         record.put(ATT_SHOW_BADGE, Boolean.toString(canShowBadge()));
         record.put(ATT_DELETED, Boolean.toString(isDeleted()));
+        record.put(ATT_DELETED_TIME_MS, Long.toString(getDeletedTimeMs()));
         record.put(ATT_GROUP, getGroup());
         record.put(ATT_BLOCKABLE_SYSTEM, isBlockable());
         record.put(ATT_ALLOW_BUBBLE, getAllowBubbles());
@@ -1182,6 +1209,7 @@
                 && mVibrationEnabled == that.mVibrationEnabled
                 && mShowBadge == that.mShowBadge
                 && isDeleted() == that.isDeleted()
+                && getDeletedTimeMs() == that.getDeletedTimeMs()
                 && isBlockable() == that.isBlockable()
                 && mAllowBubbles == that.mAllowBubbles
                 && Objects.equals(getId(), that.getId())
@@ -1205,8 +1233,8 @@
         int result = Objects.hash(getId(), getName(), mDesc, getImportance(), mBypassDnd,
                 getLockscreenVisibility(), getSound(), mLights, getLightColor(),
                 getUserLockedFields(),
-                isFgServiceShown(), mVibrationEnabled, mShowBadge, isDeleted(), getGroup(),
-                getAudioAttributes(), isBlockable(), mAllowBubbles,
+                isFgServiceShown(), mVibrationEnabled, mShowBadge, isDeleted(), getDeletedTimeMs(),
+                getGroup(), getAudioAttributes(), isBlockable(), mAllowBubbles,
                 mImportanceLockedByOEM, mImportanceLockedDefaultApp, mOriginalImportance,
                 mParentId, mConversationId, mDemoted, mImportantConvo);
         result = 31 * result + Arrays.hashCode(mVibration);
@@ -1247,6 +1275,7 @@
                 + ", mVibrationEnabled=" + mVibrationEnabled
                 + ", mShowBadge=" + mShowBadge
                 + ", mDeleted=" + mDeleted
+                + ", mDeletedTimeMs=" + mDeletedTime
                 + ", mGroup='" + mGroup + '\''
                 + ", mAudioAttributes=" + mAudioAttributes
                 + ", mBlockableSystem=" + mBlockableSystem
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index dd016a2..bbda871 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -31,7 +31,6 @@
 import android.app.job.JobSchedulerFrameworkInitializer;
 import android.app.people.PeopleManager;
 import android.app.prediction.AppPredictionManager;
-import android.app.role.RoleControllerManager;
 import android.app.role.RoleManager;
 import android.app.search.SearchUiManager;
 import android.app.slice.SliceManager;
@@ -211,6 +210,7 @@
 import android.view.textservice.TextServicesManager;
 import android.view.translation.ITranslationManager;
 import android.view.translation.TranslationManager;
+import android.view.translation.UiTranslationManager;
 
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.IBatteryStats;
@@ -1188,6 +1188,19 @@
                         return null;
                     }});
 
+        registerService(Context.UI_TRANSLATION_SERVICE, UiTranslationManager.class,
+                new CachedServiceFetcher<UiTranslationManager>() {
+                    @Override
+                    public UiTranslationManager createService(ContextImpl ctx)
+                            throws ServiceNotFoundException {
+                        IBinder b = ServiceManager.getService(Context.TRANSLATION_MANAGER_SERVICE);
+                        ITranslationManager service = ITranslationManager.Stub.asInterface(b);
+                        if (service != null) {
+                            return new UiTranslationManager(ctx.getOuterContext(), service);
+                        }
+                        return null;
+                    }});
+
         registerService(Context.SEARCH_UI_SERVICE, SearchUiManager.class,
             new CachedServiceFetcher<SearchUiManager>() {
                 @Override
@@ -1315,14 +1328,6 @@
                         return new RoleManager(ctx.getOuterContext());
                     }});
 
-        registerService(Context.ROLE_CONTROLLER_SERVICE, RoleControllerManager.class,
-                new CachedServiceFetcher<RoleControllerManager>() {
-                    @Override
-                    public RoleControllerManager createService(ContextImpl ctx)
-                            throws ServiceNotFoundException {
-                        return new RoleControllerManager(ctx.getOuterContext());
-                    }});
-
         registerService(Context.DYNAMIC_SYSTEM_SERVICE, DynamicSystemManager.class,
                 new CachedServiceFetcher<DynamicSystemManager>() {
                     @Override
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index ab0901d..ac2f223 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -63,6 +63,7 @@
 import android.os.Looper;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
+import android.os.StrictMode;
 import android.os.SystemProperties;
 import android.text.TextUtils;
 import android.util.Log;
@@ -605,7 +606,9 @@
      *     or {@code null} if no system wallpaper exists or if the calling application
      *     is not able to access the wallpaper.
      */
+    @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
     public Drawable getDrawable() {
+        assertUiContext("getDrawable");
         final ColorManagementProxy cmProxy = getColorManagementProxy();
         Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true, FLAG_SYSTEM, cmProxy);
         if (bm != null) {
@@ -673,6 +676,7 @@
      */
     public Drawable getBuiltInDrawable(int outWidth, int outHeight, boolean scaleToFit,
             float horizontalAlignment, float verticalAlignment, @SetWallpaperFlags int which) {
+        assertUiContext("getBuiltInDrawable");
         if (sGlobals.mService == null) {
             Log.w(TAG, "WallpaperService not running");
             throw new RuntimeException(new DeadSystemException());
@@ -838,6 +842,7 @@
      * null pointer if these is none.
      */
     public Drawable peekDrawable() {
+        assertUiContext("peekDrawable");
         final ColorManagementProxy cmProxy = getColorManagementProxy();
         Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false, FLAG_SYSTEM, cmProxy);
         if (bm != null) {
@@ -880,6 +885,7 @@
      */
     @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
     public Drawable peekFastDrawable() {
+        assertUiContext("peekFastDrawable");
         final ColorManagementProxy cmProxy = getColorManagementProxy();
         Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false, FLAG_SYSTEM, cmProxy);
         if (bm != null) {
@@ -1046,6 +1052,7 @@
      */
     @UnsupportedAppUsage
     public @Nullable WallpaperColors getWallpaperColors(int which, int userId) {
+        assertUiContext("getWallpaperColors");
         return sGlobals.getWallpaperColors(which, userId, mContext.getDisplayId());
     }
 
@@ -1261,6 +1268,7 @@
     @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
     public int setResource(@RawRes int resid, @SetWallpaperFlags int which)
             throws IOException {
+        assertUiContext("setResource");
         if (sGlobals.mService == null) {
             Log.w(TAG, "WallpaperService not running");
             throw new RuntimeException(new DeadSystemException());
@@ -1581,6 +1589,7 @@
      * @see #getDesiredMinimumHeight()
      */
     public int getDesiredMinimumWidth() {
+        assertUiContext("getDesiredMinimumWidth");
         if (sGlobals.mService == null) {
             Log.w(TAG, "WallpaperService not running");
             throw new RuntimeException(new DeadSystemException());
@@ -1609,6 +1618,7 @@
      * @see #getDesiredMinimumWidth()
      */
     public int getDesiredMinimumHeight() {
+        assertUiContext("getDesiredMinimumHeight");
         if (sGlobals.mService == null) {
             Log.w(TAG, "WallpaperService not running");
             throw new RuntimeException(new DeadSystemException());
@@ -1639,6 +1649,7 @@
      * @param minimumHeight Desired minimum height
      */
     public void suggestDesiredDimensions(int minimumWidth, int minimumHeight) {
+        assertUiContext("suggestDesiredDimensions");
         try {
             /**
              * The framework makes no attempt to limit the window size
@@ -1694,6 +1705,7 @@
      */
     @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_HINTS)
     public void setDisplayPadding(Rect padding) {
+        assertUiContext("setDisplayPadding");
         try {
             if (sGlobals.mService == null) {
                 Log.w(TAG, "WallpaperService not running");
@@ -1946,6 +1958,7 @@
      */
     @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
     public void clear() throws IOException {
+        assertUiContext("clear");
         setStream(openDefaultWallpaper(mContext, FLAG_SYSTEM), null, false);
     }
 
@@ -2094,6 +2107,10 @@
         return mCmProxy;
     }
 
+    private void assertUiContext(final String methodName) {
+        StrictMode.assertUiContext(mContext, methodName);
+    }
+
     /**
      * A hidden class to help {@link Globals#getCurrentWallpaperLocked} handle color management.
      * @hide
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 71af5e3..54e1ac43 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2536,6 +2536,22 @@
             "android.app.extra.PROVISIONING_SUPPORTED_MODES";
 
     /**
+     * A boolean extra which determines whether to skip the ownership disclaimer screen during the
+     * provisioning flow. The default value is {@code false}.
+     *
+     * If the value is {@code true}, it is the responsibility of the provisioning initiator to
+     * show the relevant disclaimer.
+     *
+     * <p>This extra is only respected when provided alongside the {@link
+     * #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE} intent action.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_PROVISIONING_SKIP_OWNERSHIP_DISCLAIMER =
+            "android.app.extra.PROVISIONING_SKIP_OWNERSHIP_DISCLAIMER";
+
+    /**
      * An {@link ArrayList} of {@link Integer} extra specifying the allowed provisioning modes.
      * <p>This extra will be passed to the admin app's {@link #ACTION_GET_PROVISIONING_MODE}
      * activity, whose result intent must contain {@link #EXTRA_PROVISIONING_MODE} set to one of
@@ -2564,6 +2580,30 @@
     public static final int PROVISIONING_MODE_MANAGED_PROFILE_ON_PERSONAL_DEVICE = 3;
 
     /**
+     * A {@code boolean} flag that indicates whether the provisioning flow should return before
+     * starting the admin app's {@link #ACTION_ADMIN_POLICY_COMPLIANCE} handler. The default value
+     * is {@code true}.
+     *
+     * <p>If this extra is set to {@code true}, then when the provisioning flow returns back to the
+     * provisioning initiator, provisioning will not be complete. The provisioning initiator can
+     * use this opportunity to do its own preparatory steps prior to the launch of the admin app's
+     * {@link #ACTION_ADMIN_POLICY_COMPLIANCE} handler. It is the responsibility of the
+     * provisioning initiator to ensure that the provisioning flow is then resumed and completed.
+     *
+     * <p>If this extra is set to {@code false}, then when the provisioning flow returns back to
+     * the provisioning initiator, provisioning will be complete. Note that device owner
+     * provisioning is not currently supported for the this scenario.
+     *
+     * <p>This extra is only respected when provided alongside the {@link
+     * #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE} intent action.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_PROVISIONING_RETURN_BEFORE_POLICY_COMPLIANCE =
+            "android.app.extra.PROVISIONING_RETURN_BEFORE_POLICY_COMPLIANCE";
+
+    /**
      * Activity action: Starts the administrator to show policy compliance for the provisioning.
      * This action is used any time that the administrator has an opportunity to show policy
      * compliance before the end of setup wizard. This could happen as part of the admin-integrated
@@ -2690,6 +2730,60 @@
     /** @hide */
     @TestApi
     public static final int OPERATION_SET_USER_CONTROL_DISABLED_PACKAGES = 22;
+    /** @hide */
+    @TestApi
+    public static final int OPERATION_CLEAR_APPLICATION_USER_DATA = 23;
+    /** @hide */
+    @TestApi
+    public static final int OPERATION_INSTALL_CA_CERT = 24;
+    /** @hide */
+    @TestApi
+    public static final int OPERATION_INSTALL_KEY_PAIR = 25;
+    /** @hide */
+    @TestApi
+    public static final int OPERATION_INSTALL_SYSTEM_UPDATE = 26;
+    /** @hide */
+    @TestApi
+    public static final int OPERATION_REMOVE_ACTIVE_ADMIN = 27;
+    /** @hide */
+    @TestApi
+    public static final int OPERATION_REMOVE_KEY_PAIR = 28;
+    /** @hide */
+    @TestApi
+    public static final int OPERATION_REQUEST_BUGREPORT = 29;
+    /** @hide */
+    @TestApi
+    public static final int OPERATION_SET_ALWAYS_ON_VPN_PACKAGE = 30;
+    /** @hide */
+    @TestApi
+    public static final int OPERATION_SET_CAMERA_DISABLED = 31;
+    /** @hide */
+    @TestApi
+    public static final int OPERATION_SET_FACTORY_RESET_PROTECTION_POLICY = 32;
+    /** @hide */
+    @TestApi
+    public static final int OPERATION_SET_GLOBAL_PRIVATE_DNS = 33;
+    /** @hide */
+    @TestApi
+    public static final int OPERATION_SET_LOGOUT_ENABLED = 34;
+    /** @hide */
+    @TestApi
+    public static final int OPERATION_SET_MASTER_VOLUME_MUTED = 35;
+    /** @hide */
+    @TestApi
+    public static final int OPERATION_SET_OVERRIDE_APNS_ENABLED = 36;
+    /** @hide */
+    @TestApi
+    public static final int OPERATION_SET_PERMISSION_GRANT_STATE = 37;
+    /** @hide */
+    @TestApi
+    public static final int OPERATION_SET_PERMISSION_POLICY = 38;
+    /** @hide */
+    @TestApi
+    public static final int OPERATION_SET_RESTRICTIONS_PROVIDER = 39;
+    /** @hide */
+    @TestApi
+    public static final int OPERATION_UNINSTALL_CA_CERT = 40;
 
     private static final String PREFIX_OPERATION = "OPERATION_";
 
@@ -2716,7 +2810,25 @@
             OPERATION_SET_LOCK_TASK_PACKAGES,
             OPERATION_SET_PACKAGES_SUSPENDED,
             OPERATION_SET_TRUST_AGENT_CONFIGURATION,
-            OPERATION_SET_USER_CONTROL_DISABLED_PACKAGES
+            OPERATION_SET_USER_CONTROL_DISABLED_PACKAGES,
+            OPERATION_CLEAR_APPLICATION_USER_DATA,
+            OPERATION_INSTALL_CA_CERT,
+            OPERATION_INSTALL_KEY_PAIR,
+            OPERATION_INSTALL_SYSTEM_UPDATE,
+            OPERATION_REMOVE_ACTIVE_ADMIN,
+            OPERATION_REMOVE_KEY_PAIR,
+            OPERATION_REQUEST_BUGREPORT,
+            OPERATION_SET_ALWAYS_ON_VPN_PACKAGE,
+            OPERATION_SET_CAMERA_DISABLED,
+            OPERATION_SET_FACTORY_RESET_PROTECTION_POLICY,
+            OPERATION_SET_GLOBAL_PRIVATE_DNS,
+            OPERATION_SET_LOGOUT_ENABLED,
+            OPERATION_SET_MASTER_VOLUME_MUTED,
+            OPERATION_SET_OVERRIDE_APNS_ENABLED,
+            OPERATION_SET_PERMISSION_GRANT_STATE,
+            OPERATION_SET_PERMISSION_POLICY,
+            OPERATION_SET_RESTRICTIONS_PROVIDER,
+            OPERATION_UNINSTALL_CA_CERT
     })
     @Retention(RetentionPolicy.SOURCE)
     public static @interface DevicePolicyOperation {
@@ -9823,7 +9935,7 @@
      * Designates a specific service component as the provider for making permission requests of a
      * local or remote administrator of the user.
      * <p/>
-     * Only a profile owner can designate the restrictions provider.
+     * Only a device owner or profile owner can designate the restrictions provider.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param provider The component name of the service that implements
diff --git a/core/java/android/app/role/RoleControllerManager.java b/core/java/android/app/role/RoleControllerManager.java
index 8dde2c5..ba1f612 100644
--- a/core/java/android/app/role/RoleControllerManager.java
+++ b/core/java/android/app/role/RoleControllerManager.java
@@ -20,8 +20,6 @@
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
-import android.annotation.SystemService;
-import android.annotation.TestApi;
 import android.app.ActivityThread;
 import android.content.ComponentName;
 import android.content.Context;
@@ -48,8 +46,6 @@
  *
  * @hide
  */
-@SystemService(Context.ROLE_CONTROLLER_SERVICE)
-@TestApi
 public class RoleControllerManager {
 
     private static final String LOG_TAG = RoleControllerManager.class.getSimpleName();
@@ -199,32 +195,11 @@
     }
 
     /**
-     * @see RoleControllerService#onIsApplicationQualifiedForRole(String, String)
-     *
-     * @deprecated Use {@link #isApplicationVisibleForRole(String, String, Executor, Consumer)}
-     *             instead.
-     *
-     * @hide
-     */
-    @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
-    public void isApplicationQualifiedForRole(@NonNull String roleName, @NonNull String packageName,
-            @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
-        AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> {
-            AndroidFuture<Bundle> future = new AndroidFuture<>();
-            service.isApplicationQualifiedForRole(roleName, packageName,
-                    new RemoteCallback(future::complete));
-            return future;
-        });
-        propagateCallback(operation, "isApplicationQualifiedForRole", executor, callback);
-    }
-
-    /**
      * @see RoleControllerService#onIsApplicationVisibleForRole(String, String)
      *
      * @hide
      */
     @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
-    @TestApi
     public void isApplicationVisibleForRole(@NonNull String roleName, @NonNull String packageName,
             @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
         AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> {
@@ -242,7 +217,6 @@
      * @hide
      */
     @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
-    @TestApi
     public void isRoleVisible(@NonNull String roleName,
             @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
         AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> {
diff --git a/core/java/android/app/role/RoleManager.java b/core/java/android/app/role/RoleManager.java
index 8b2e07b..0fcf44d 100644
--- a/core/java/android/app/role/RoleManager.java
+++ b/core/java/android/app/role/RoleManager.java
@@ -174,6 +174,9 @@
     @NonNull
     private final Object mListenersLock = new Object();
 
+    @NonNull
+    private final RoleControllerManager mRoleControllerManager;
+
     /**
      * @hide
      */
@@ -181,6 +184,7 @@
         mContext = context;
         mService = IRoleManager.Stub.asInterface(ServiceManager.getServiceOrThrow(
                 Context.ROLE_SERVICE));
+        mRoleControllerManager = new RoleControllerManager(context);
     }
 
     /**
@@ -676,6 +680,44 @@
         }
     }
 
+    /**
+     * Check whether a role should be visible to user.
+     *
+     * @param roleName name of the role to check for
+     * @param executor the executor to execute callback on
+     * @param callback the callback to receive whether the role should be visible to user
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
+    @TestApi
+    public void isRoleVisible(@NonNull String roleName,
+            @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
+        mRoleControllerManager.isRoleVisible(roleName, executor, callback);
+    }
+
+    /**
+     * Check whether an application is visible for a role.
+     *
+     * While an application can be qualified for a role, it can still stay hidden from user (thus
+     * not visible). If an application is visible for a role, we may show things related to the role
+     * for it, e.g. showing an entry pointing to the role settings in its application info page.
+     *
+     * @param roleName the name of the role to check for
+     * @param packageName the package name of the application to check for
+     * @param executor the executor to execute callback on
+     * @param callback the callback to receive whether the application is visible for the role
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
+    @TestApi
+    public void isApplicationVisibleForRole(@NonNull String roleName, @NonNull String packageName,
+            @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
+        mRoleControllerManager.isApplicationVisibleForRole(roleName, packageName, executor,
+                callback);
+    }
+
     private static class OnRoleHoldersChangedListenerDelegate
             extends IOnRoleHoldersChangedListener.Stub {
 
diff --git a/core/java/android/app/search/OWNERS b/core/java/android/app/search/OWNERS
new file mode 100644
index 0000000..92835c2
--- /dev/null
+++ b/core/java/android/app/search/OWNERS
@@ -0,0 +1,2 @@
+hyunyoungs@google.com
+sfufa@google.com
diff --git a/core/java/android/app/search/SearchAction.java b/core/java/android/app/search/SearchAction.java
index 158f9f3..a76154a 100644
--- a/core/java/android/app/search/SearchAction.java
+++ b/core/java/android/app/search/SearchAction.java
@@ -70,20 +70,20 @@
 
     SearchAction(Parcel in) {
         mId = in.readString();
-        mIcon = Icon.CREATOR.createFromParcel(in);
         mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+        mIcon = in.readTypedObject(Icon.CREATOR);
         mSubtitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
         mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
-        mPendingIntent = PendingIntent.CREATOR.createFromParcel(in);
-        mIntent = Intent.CREATOR.createFromParcel(in);
+        mPendingIntent = in.readTypedObject(PendingIntent.CREATOR);
+        mIntent = in.readTypedObject(Intent.CREATOR);
         mUserHandle = in.readTypedObject(UserHandle.CREATOR);
-        mExtras = in.readBundle();
+        mExtras = in.readTypedObject(Bundle.CREATOR);
     }
 
     private SearchAction(
             @NonNull String id,
-            @Nullable Icon icon,
             @NonNull CharSequence title,
+            @Nullable Icon icon,
             @Nullable CharSequence subtitle,
             @Nullable CharSequence contentDescription,
             @Nullable PendingIntent pendingIntent,
@@ -91,8 +91,8 @@
             @Nullable UserHandle userHandle,
             @Nullable Bundle extras) {
         mId = Objects.requireNonNull(id);
-        mIcon = icon;
         mTitle = Objects.requireNonNull(title);
+        mIcon = icon;
         mSubtitle = subtitle;
         mContentDescription = contentDescription;
         mPendingIntent = pendingIntent;
@@ -192,14 +192,14 @@
     @Override
     public void writeToParcel(@NonNull Parcel out, int flags) {
         out.writeString(mId);
-        out.writeTypedObject(mIcon, flags);
         TextUtils.writeToParcel(mTitle, out, flags);
+        out.writeTypedObject(mIcon, flags);
         TextUtils.writeToParcel(mSubtitle, out, flags);
         TextUtils.writeToParcel(mContentDescription, out, flags);
         out.writeTypedObject(mPendingIntent, flags);
         out.writeTypedObject(mIntent, flags);
         out.writeTypedObject(mUserHandle, flags);
-        out.writeBundle(mExtras);
+        out.writeTypedObject(mExtras, flags);
     }
 
     @Override
@@ -235,13 +235,13 @@
         @NonNull
         private String mId;
 
-        @Nullable
-        private Icon mIcon;
-
         @NonNull
         private CharSequence mTitle;
 
         @Nullable
+        private Icon mIcon;
+
+        @Nullable
         private CharSequence mSubtitle;
 
         @Nullable
@@ -337,7 +337,7 @@
          */
         @NonNull
         public SearchAction build() {
-            return new SearchAction(mId, mIcon, mTitle, mSubtitle, mContentDescription,
+            return new SearchAction(mId, mTitle, mIcon, mSubtitle, mContentDescription,
                     mPendingIntent, mIntent, mUserHandle, mExtras);
         }
     }
diff --git a/core/java/android/app/usage/StorageStats.java b/core/java/android/app/usage/StorageStats.java
index 4757557..8d25d7b 100644
--- a/core/java/android/app/usage/StorageStats.java
+++ b/core/java/android/app/usage/StorageStats.java
@@ -32,6 +32,7 @@
     /** {@hide} */ public long codeBytes;
     /** {@hide} */ public long dataBytes;
     /** {@hide} */ public long cacheBytes;
+    /** {@hide} */ public long externalCacheBytes;
 
     /**
      * Return the size of app. This includes {@code APK} files, optimized
@@ -77,6 +78,17 @@
         return cacheBytes;
     }
 
+    /**
+     * Return the size of all cached data in the primary external/shared storage.
+     * This includes files stored under
+     * {@link Context#getExternalCacheDir()}.
+     * <p>
+     * Cached data is isolated for each user on a multiuser device.
+     */
+    public @BytesLong long getExternalCacheBytes() {
+        return externalCacheBytes;
+    }
+
     /** {@hide} */
     public StorageStats() {
     }
@@ -86,6 +98,7 @@
         this.codeBytes = in.readLong();
         this.dataBytes = in.readLong();
         this.cacheBytes = in.readLong();
+        this.externalCacheBytes = in.readLong();
     }
 
     @Override
@@ -98,6 +111,7 @@
         dest.writeLong(codeBytes);
         dest.writeLong(dataBytes);
         dest.writeLong(cacheBytes);
+        dest.writeLong(externalCacheBytes);
     }
 
     public static final @android.annotation.NonNull Creator<StorageStats> CREATOR = new Creator<StorageStats>() {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 5ccceca..2190140 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4520,6 +4520,15 @@
     public static final String TRANSLATION_MANAGER_SERVICE = "transformer";
 
     /**
+     * Official published name of the translation service which supports ui translation function.
+     *
+     * @hide
+     * @see #getSystemService(String)
+     */
+    @SystemApi
+    public static final String UI_TRANSLATION_SERVICE = "ui_translation";
+
+    /**
      * Used for getting content selections and classifications for task snapshots.
      *
      * @hide
@@ -4833,16 +4842,6 @@
     public static final String ROLE_SERVICE = "role";
 
     /**
-     * Official published name of the (internal) role controller service.
-     *
-     * @see #getSystemService(String)
-     * @see android.app.role.RoleControllerService
-     *
-     * @hide
-     */
-    public static final String ROLE_CONTROLLER_SERVICE = "role_controller";
-
-    /**
      * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.hardware.camera2.CameraManager} for interacting with
      * camera devices.
@@ -5096,9 +5095,7 @@
      * Service to capture a bugreport.
      * @see #getSystemService(String)
      * @see android.os.BugreportManager
-     * @hide
      */
-    @SystemApi
     public static final String BUGREPORT_SERVICE = "bugreport";
 
     /**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 13a1381..7843d97 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3660,7 +3660,7 @@
 
     /**
      * Broadcast sent by the system when a user is started. Carries an extra
-     * EXTRA_USER_HANDLE that has the userHandle of the user.  This is only sent to
+     * {@link EXTRA_USER_HANDLE} that has the userHandle of the user.  This is only sent to
      * registered receivers, not manifest receivers.  It is sent to the user
      * that has been started.  This is sent as a foreground
      * broadcast, since it is part of a visible user interaction; be as quick
@@ -3672,7 +3672,7 @@
 
     /**
      * Broadcast sent when a user is in the process of starting.  Carries an extra
-     * EXTRA_USER_HANDLE that has the userHandle of the user.  This is only
+     * {@link EXTRA_USER_HANDLE} that has the userHandle of the user.  This is only
      * sent to registered receivers, not manifest receivers.  It is sent to all
      * users (including the one that is being started).  You must hold
      * {@link android.Manifest.permission#INTERACT_ACROSS_USERS} to receive
@@ -3689,7 +3689,7 @@
 
     /**
      * Broadcast sent when a user is going to be stopped.  Carries an extra
-     * EXTRA_USER_HANDLE that has the userHandle of the user.  This is only
+     * {@link EXTRA_USER_HANDLE} that has the userHandle of the user.  This is only
      * sent to registered receivers, not manifest receivers.  It is sent to all
      * users (including the one that is being stopped).  You must hold
      * {@link android.Manifest.permission#INTERACT_ACROSS_USERS} to receive
@@ -3707,7 +3707,7 @@
 
     /**
      * Broadcast sent to the system when a user is stopped. Carries an extra
-     * EXTRA_USER_HANDLE that has the userHandle of the user.  This is similar to
+     * {@link EXTRA_USER_HANDLE} that has the userHandle of the user.  This is similar to
      * {@link #ACTION_PACKAGE_RESTARTED}, but for an entire user instead of a
      * specific package.  This is only sent to registered receivers, not manifest
      * receivers.  It is sent to all running users <em>except</em> the one that
@@ -3811,6 +3811,22 @@
             "android.intent.action.MANAGED_PROFILE_UNAVAILABLE";
 
     /**
+     * Broadcast sent to the parent user when an associated profile has been started and unlocked.
+     * Carries an extra {@link #EXTRA_USER} that specifies the {@link UserHandle} of the profile.
+     * This is only sent to registered receivers, not manifest receivers.
+     */
+    public static final String ACTION_PROFILE_ACCESSIBLE =
+            "android.intent.action.PROFILE_ACCESSIBLE";
+
+    /**
+     * Broadcast sent to the parent user when an associated profile has stopped.
+     * Carries an extra {@link #EXTRA_USER} that specifies the {@link UserHandle} of the profile.
+     * This is only sent to registered receivers, not manifest receivers.
+     */
+    public static final String ACTION_PROFILE_INACCESSIBLE =
+            "android.intent.action.PROFILE_INACCESSIBLE";
+
+    /**
      * Broadcast sent to the system user when the 'device locked' state changes for any user.
      * Carries an extra {@link #EXTRA_USER_HANDLE} that specifies the ID of the user for which
      * the device was locked or unlocked.
diff --git a/core/java/android/content/pm/AppSearchPerson.java b/core/java/android/content/pm/AppSearchPerson.java
new file mode 100644
index 0000000..045c55f
--- /dev/null
+++ b/core/java/android/content/pm/AppSearchPerson.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.Person;
+import android.app.appsearch.AppSearchSchema;
+import android.app.appsearch.GenericDocument;
+import android.net.UriCodec;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Objects;
+import java.util.UUID;
+
+/**
+ * @hide
+ */
+public class AppSearchPerson extends GenericDocument {
+
+    /** The name of the schema type for {@link Person} documents.*/
+    public static final String SCHEMA_TYPE = "Person";
+
+    public static final String KEY_NAME = "name";
+    public static final String KEY_KEY = "key";
+    public static final String KEY_IS_BOT = "isBot";
+    public static final String KEY_IS_IMPORTANT = "isImportant";
+
+    private AppSearchPerson(@NonNull GenericDocument document) {
+        super(document);
+    }
+
+    public static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
+            .addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_NAME)
+                    .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                    .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
+                    .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+                    .build()
+
+            ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_KEY)
+                    .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                    .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
+                    .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+                    .build()
+
+            ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_IS_BOT)
+                    .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+                    .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
+                    .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+                    .build()
+
+            ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_IS_IMPORTANT)
+                    .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+                    .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
+                    .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+                    .build()
+
+            ).build();
+
+    /** hide */
+    @NonNull
+    public static AppSearchPerson instance(@NonNull final Person person) {
+        Objects.requireNonNull(person);
+        final String id;
+        if (person.getUri() != null) {
+            id = person.getUri();
+        } else {
+            // NOTE: an identifier is required even when uri is null.
+            id = UUID.randomUUID().toString();
+        }
+        return new Builder(id).setName(person.getName())
+                .setKey(person.getKey()).setIsBot(person.isBot())
+                .setIsImportant(person.isImportant()).build();
+    }
+
+    /** hide */
+    @NonNull
+    public Person toPerson() {
+        String uri;
+        try {
+            uri = UriCodec.decode(
+                    getUri(), false /* convertPlus */, StandardCharsets.UTF_8,
+                    true /* throwOnFailure */);
+        } catch (IllegalArgumentException e) {
+            uri = null;
+        }
+        return new Person.Builder().setName(getPropertyString(KEY_NAME))
+                .setUri(uri).setKey(getPropertyString(KEY_KEY))
+                .setBot(getPropertyBoolean(KEY_IS_BOT))
+                .setImportant(getPropertyBoolean(KEY_IS_IMPORTANT)).build();
+    }
+
+    /** @hide */
+    @VisibleForTesting
+    public static class Builder extends GenericDocument.Builder<Builder> {
+
+        public Builder(@NonNull final String id) {
+            super(id, SCHEMA_TYPE);
+        }
+
+        /** @hide */
+        @NonNull
+        public Builder setName(@Nullable final CharSequence name) {
+            if (name != null) {
+                setPropertyString(KEY_NAME, name.toString());
+            }
+            return this;
+        }
+
+        /** @hide */
+        @NonNull
+        public Builder setKey(@Nullable final String key) {
+            if (key != null) {
+                setPropertyString(KEY_KEY, key);
+            }
+            return this;
+        }
+
+        /** @hide */
+        @NonNull
+        public Builder setIsBot(final boolean isBot) {
+            setPropertyBoolean(KEY_IS_BOT, isBot);
+            return this;
+        }
+
+        /** @hide */
+        @NonNull
+        public Builder setIsImportant(final boolean isImportant) {
+            setPropertyBoolean(KEY_IS_IMPORTANT, isImportant);
+            return this;
+        }
+
+        @NonNull
+        @Override
+        public AppSearchPerson build() {
+            return new AppSearchPerson(super.build());
+        }
+    }
+}
diff --git a/core/java/android/content/pm/AppSearchShortcutInfo.java b/core/java/android/content/pm/AppSearchShortcutInfo.java
new file mode 100644
index 0000000..14b8df8
--- /dev/null
+++ b/core/java/android/content/pm/AppSearchShortcutInfo.java
@@ -0,0 +1,616 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.Person;
+import android.app.appsearch.AppSearchSchema;
+import android.app.appsearch.GenericDocument;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.LocusId;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.os.PersistableBundle;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.ArraySet;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * @hide
+ */
+public class AppSearchShortcutInfo extends GenericDocument {
+
+    /** The name of the schema type for {@link ShortcutInfo} documents.*/
+    public static final String SCHEMA_TYPE = "Shortcut";
+
+    public static final String KEY_PACKAGE_NAME = "packageName";
+    public static final String KEY_ACTIVITY = "activity";
+    public static final String KEY_TITLE = "title";
+    public static final String KEY_TEXT = "text";
+    public static final String KEY_DISABLED_MESSAGE = "disabledMessage";
+    public static final String KEY_CATEGORIES = "categories";
+    public static final String KEY_INTENTS = "intents";
+    public static final String KEY_INTENT_PERSISTABLE_EXTRAS = "intentPersistableExtras";
+    public static final String KEY_PERSON = "person";
+    public static final String KEY_LOCUS_ID = "locusId";
+    public static final String KEY_RANK = "rank";
+    public static final String KEY_EXTRAS = "extras";
+    public static final String KEY_FLAGS = "flags";
+    public static final String KEY_ICON_RES_ID = "iconResId";
+    public static final String KEY_ICON_RES_NAME = "iconResName";
+    public static final String KEY_ICON_URI = "iconUri";
+    public static final String KEY_BITMAP_PATH = "bitmapPath";
+    public static final String KEY_DISABLED_REASON = "disabledReason";
+
+    public static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
+            .addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_PACKAGE_NAME)
+                    .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+                    .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+                    .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+                    .build()
+
+            ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_ACTIVITY)
+                    .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                    .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+                    .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+                    .build()
+
+            ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_TITLE)
+                    .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                    .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+                    .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES)
+                    .build()
+
+            ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_TEXT)
+                    .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                    .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+                    .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES)
+                    .build()
+
+            ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_DISABLED_MESSAGE)
+                    .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                    .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
+                    .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+                    .build()
+
+            ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_CATEGORIES)
+                    .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+                    .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+                    .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+                    .build()
+
+            ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_INTENTS)
+                    .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+                    .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
+                    .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+                    .build()
+
+            ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_INTENT_PERSISTABLE_EXTRAS)
+                    .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+                    .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
+                    .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+                    .build()
+
+            ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_PERSON)
+                    .setSchemaType(AppSearchPerson.SCHEMA_TYPE)
+                    .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOCUMENT)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+                    .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
+                    .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+                    .build()
+
+            ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_LOCUS_ID)
+                    .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                    .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+                    .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+                    .build()
+
+            ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_RANK)
+                    .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                    .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
+                    .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+                    .build()
+
+            ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_EXTRAS)
+                    .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                    .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
+                    .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+                    .build()
+
+            ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_FLAGS)
+                    .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+                    .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+                    .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+                    .build()
+
+            ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_ICON_RES_ID)
+                    .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                    .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
+                    .setIndexingType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
+                    .build()
+
+            ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_ICON_RES_NAME)
+                    .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                    .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
+                    .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+                    .build()
+
+            ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_ICON_URI)
+                    .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                    .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
+                    .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+                    .build()
+
+            ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_BITMAP_PATH)
+                    .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                    .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
+                    .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+                    .build()
+
+            ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_DISABLED_REASON)
+                    .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+                    .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+                    .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+                    .build()
+
+            ).build();
+
+    public AppSearchShortcutInfo(@NonNull GenericDocument document) {
+        super(document);
+    }
+
+    /**
+     * @hide
+     */
+    @NonNull
+    public static AppSearchShortcutInfo instance(@NonNull final ShortcutInfo shortcutInfo) {
+        Objects.requireNonNull(shortcutInfo);
+        return new Builder(shortcutInfo.getId())
+                .setActivity(shortcutInfo.getActivity())
+                .setPackageName(shortcutInfo.getPackage())
+                .setTitle(shortcutInfo.getShortLabel())
+                .setText(shortcutInfo.getLongLabel())
+                .setDisabledMessage(shortcutInfo.getDisabledMessage())
+                .setCategories(shortcutInfo.getCategories())
+                .setIntents(shortcutInfo.getIntents())
+                .setRank(shortcutInfo.getRank())
+                .setExtras(shortcutInfo.getExtras())
+                .setCreationTimestampMillis(shortcutInfo.getLastChangedTimestamp())
+                .setFlags(shortcutInfo.getFlags())
+                .setIconResId(shortcutInfo.getIconResourceId())
+                .setIconResName(shortcutInfo.getIconResName())
+                .setBitmapPath(shortcutInfo.getBitmapPath())
+                .setIconUri(shortcutInfo.getIconUri())
+                .setDisabledReason(shortcutInfo.getDisabledReason())
+                .setPersons(shortcutInfo.getPersons())
+                .setLocusId(shortcutInfo.getLocusId())
+                .build();
+    }
+
+    /**
+     * @hide
+     */
+    @NonNull
+    public ShortcutInfo toShortcutInfo() {
+        return toShortcutInfo(UserHandle.myUserId());
+    }
+
+    /**
+     * @hide
+     * TODO: This should be @SystemApi when AppSearchShortcutInfo unhides.
+     */
+    @NonNull
+    public ShortcutInfo toShortcutInfo(@UserIdInt final int userId) {
+        final String packageName = getPropertyString(KEY_PACKAGE_NAME);
+        final String activityString = getPropertyString(KEY_ACTIVITY);
+        final ComponentName activity = activityString == null
+                ? null : ComponentName.unflattenFromString(activityString);
+        // TODO: proper icon handling
+        // NOTE: bitmap based icons are currently saved in side-channel (see ShortcutBitmapSaver),
+        // re-creating Icon object at creation time implies turning this function into async since
+        // loading bitmap is I/O bound. Since ShortcutInfo#getIcon is already annotated with
+        // @hide and @UnsupportedAppUsage, we could migrate existing usage in platform with
+        // LauncherApps#getShortcutIconDrawable instead.
+        final Icon icon = null;
+        final String title = getPropertyString(KEY_TITLE);
+        final String text = getPropertyString(KEY_TEXT);
+        final String disabledMessage = getPropertyString(KEY_DISABLED_MESSAGE);
+        final String[] categories = getPropertyStringArray(KEY_CATEGORIES);
+        final Set<String> categoriesSet = categories == null
+                ? new ArraySet<>() : new ArraySet<>(Arrays.asList(categories));
+        final String[] intentsStrings = getPropertyStringArray(KEY_INTENTS);
+        final Intent[] intents = intentsStrings == null
+                ? null : Arrays.stream(intentsStrings).map(uri -> {
+                    try {
+                        return Intent.parseUri(uri, /* flags =*/ 0);
+                    } catch (URISyntaxException e) {
+                        // ignore malformed entry
+                    }
+                    return null;
+                }).toArray(Intent[]::new);
+        final byte[][] intentExtrasesBytes = getPropertyBytesArray(KEY_INTENT_PERSISTABLE_EXTRAS);
+        final Bundle[] intentExtrases = intentExtrasesBytes == null
+                ? null : Arrays.stream(intentExtrasesBytes)
+                .map(this::transformToBundle).toArray(Bundle[]::new);
+        if (intents != null) {
+            for (int i = 0; i < intents.length; i++) {
+                final Intent intent = intents[i];
+                if (intent != null) {
+                    intent.replaceExtras(intentExtrases[i].size() == 0 ? null : intentExtrases[i]);
+                }
+            }
+        }
+        final Person[] persons = parsePerson(getPropertyDocumentArray(KEY_PERSON));
+        final String locusIdString = getPropertyString(KEY_LOCUS_ID);
+        final LocusId locusId = locusIdString == null ? null : new LocusId(locusIdString);
+        final int rank = (int) getPropertyLong(KEY_RANK);
+        final byte[] extrasByte = getPropertyBytes(KEY_EXTRAS);
+        final PersistableBundle extras = transformToPersistableBundle(extrasByte);
+        final int flags = parseFlags(getPropertyLongArray(KEY_FLAGS));
+        final int iconResId = (int) getPropertyLong(KEY_ICON_RES_ID);
+        final String iconResName = getPropertyString(KEY_ICON_RES_NAME);
+        final String iconUri = getPropertyString(KEY_ICON_URI);
+        final String bitmapPath = getPropertyString(KEY_BITMAP_PATH);
+        final int disabledReason = (int) getPropertyLong(KEY_DISABLED_REASON);
+        return new ShortcutInfo(
+                userId, getUri(), packageName, activity, icon, title, 0, null,
+                text, 0, null, disabledMessage, 0, null,
+                categoriesSet, intents, rank, extras,
+                getCreationTimestampMillis(), flags, iconResId, iconResName, bitmapPath, iconUri,
+                disabledReason, persons, locusId);
+    }
+
+    /** @hide */
+    @VisibleForTesting
+    public static class Builder extends GenericDocument.Builder<Builder> {
+
+        public Builder(String id) {
+            super(id, SCHEMA_TYPE);
+        }
+
+        /**
+         * @hide
+         */
+        @NonNull
+        public Builder setLocusId(@Nullable final LocusId locusId) {
+            if (locusId != null) {
+                setPropertyString(KEY_LOCUS_ID, locusId.getId());
+            }
+            return this;
+        }
+
+        /**
+         * @hide
+         */
+        @NonNull
+        public Builder setActivity(@Nullable final ComponentName activity) {
+            if (activity != null) {
+                setPropertyString(KEY_ACTIVITY, activity.flattenToShortString());
+            }
+            return this;
+        }
+
+        /**
+         * @hide
+         */
+        @NonNull
+        public Builder setTitle(@Nullable final CharSequence shortLabel) {
+            if (!TextUtils.isEmpty(shortLabel)) {
+                setPropertyString(KEY_TITLE, Preconditions.checkStringNotEmpty(
+                        shortLabel, "shortLabel cannot be empty").toString());
+            }
+            return this;
+        }
+
+        /**
+         * @hide
+         */
+        @NonNull
+        public Builder setText(@Nullable final CharSequence longLabel) {
+            if (!TextUtils.isEmpty(longLabel)) {
+                setPropertyString(KEY_TEXT, Preconditions.checkStringNotEmpty(
+                        longLabel, "longLabel cannot be empty").toString());
+            }
+            return this;
+
+        }
+
+        /**
+         * @hide
+         */
+        @NonNull
+        public Builder setDisabledMessage(@Nullable final CharSequence disabledMessage) {
+            if (!TextUtils.isEmpty(disabledMessage)) {
+                setPropertyString(KEY_DISABLED_MESSAGE, Preconditions.checkStringNotEmpty(
+                        disabledMessage, "disabledMessage cannot be empty").toString());
+            }
+            return this;
+        }
+
+        /**
+         * @hide
+         */
+        @NonNull
+        public Builder setCategories(@Nullable final Set<String> categories) {
+            if (categories != null && !categories.isEmpty()) {
+                setPropertyString(KEY_CATEGORIES, categories.stream().toArray(String[]::new));
+            }
+            return this;
+        }
+
+        /**
+         * @hide
+         */
+        @NonNull
+        public Builder setIntent(@Nullable final Intent intent) {
+            if (intent == null) {
+                return this;
+            }
+            return setIntents(new Intent[]{intent});
+        }
+
+        /**
+         * @hide
+         */
+        @NonNull
+        public Builder setIntents(@Nullable final Intent[] intents) {
+            if (intents == null || intents.length == 0) {
+                return this;
+            }
+            for (Intent intent : intents) {
+                Objects.requireNonNull(intent, "intents cannot contain null");
+                Objects.requireNonNull(intent.getAction(), "intent's action must be set");
+            }
+            final byte[][] intentExtrases = new byte[intents.length][];
+            for (int i = 0; i < intents.length; i++) {
+                final Intent intent = intents[i];
+                final Bundle extras = intent.getExtras();
+                intentExtrases[i] = extras == null
+                        ? new byte[0] : transformToByteArray(new PersistableBundle(extras));
+            }
+
+            setPropertyString(KEY_INTENTS, Arrays.stream(intents).map(it ->
+                    it.toUri(0)).toArray(String[]::new));
+            setPropertyBytes(KEY_INTENT_PERSISTABLE_EXTRAS, intentExtrases);
+            return this;
+        }
+
+        /**
+         * @hide
+         */
+        @NonNull
+        public Builder setPerson(@Nullable final Person person) {
+            if (person == null) {
+                return this;
+            }
+            return setPersons(new Person[]{person});
+        }
+
+        /**
+         * @hide
+         */
+        @NonNull
+        public Builder setPersons(@Nullable final Person[] persons) {
+            if (persons == null || persons.length == 0) {
+                return this;
+            }
+            setPropertyDocument(KEY_PERSON,
+                    Arrays.stream(persons).map(person -> AppSearchPerson.instance(
+                            Objects.requireNonNull(person, "persons cannot contain null"))
+                    ).toArray(AppSearchPerson[]::new));
+            return this;
+        }
+
+        /**
+         * @hide
+         */
+        @NonNull
+        public Builder setRank(final int rank) {
+            Preconditions.checkArgument((0 <= rank),
+                    "Rank cannot be negative or bigger than MAX_RANK");
+            setPropertyLong(KEY_RANK, rank);
+            return this;
+        }
+
+        /**
+         * @hide
+         */
+        @NonNull
+        public Builder setExtras(@Nullable final PersistableBundle extras) {
+            if (extras != null) {
+                setPropertyBytes(KEY_EXTRAS, transformToByteArray(extras));
+            }
+            return this;
+        }
+
+        /**
+         * @hide
+         */
+        public Builder setPackageName(@Nullable final String packageName) {
+            if (!TextUtils.isEmpty(packageName)) {
+                setPropertyString(KEY_PACKAGE_NAME, packageName);
+            }
+            return this;
+        }
+
+        /**
+         * @hide
+         */
+        public Builder setFlags(@ShortcutInfo.ShortcutFlags final int flags) {
+            setPropertyLong(KEY_FLAGS, flattenFlags(flags));
+            return this;
+        }
+
+        /**
+         * @hide
+         */
+        @NonNull
+        public Builder setIconResId(@Nullable final int iconResId) {
+            setPropertyLong(KEY_ICON_RES_ID, iconResId);
+            return this;
+        }
+
+        /**
+         * @hide
+         */
+        public Builder setIconResName(@Nullable final String iconResName) {
+            if (!TextUtils.isEmpty(iconResName)) {
+                setPropertyString(KEY_ICON_RES_NAME, iconResName);
+            }
+            return this;
+        }
+
+        /**
+         * @hide
+         */
+        public Builder setBitmapPath(@Nullable final String bitmapPath) {
+            if (!TextUtils.isEmpty(bitmapPath)) {
+                setPropertyString(KEY_BITMAP_PATH, bitmapPath);
+            }
+            return this;
+        }
+
+        /**
+         * @hide
+         */
+        public Builder setIconUri(@Nullable final String iconUri) {
+            if (!TextUtils.isEmpty(iconUri)) {
+                setPropertyString(KEY_ICON_URI, iconUri);
+            }
+            return this;
+        }
+
+        /**
+         * @hide
+         */
+        public Builder setDisabledReason(@ShortcutInfo.DisabledReason final int disabledReason) {
+            setPropertyLong(KEY_DISABLED_REASON, disabledReason);
+            return this;
+        }
+
+        /**
+         * @hide
+         */
+        @NonNull
+        @Override
+        public AppSearchShortcutInfo build() {
+            return new AppSearchShortcutInfo(super.build());
+        }
+    }
+
+    /**
+     * Convert PersistableBundle into byte[] for persistence.
+     */
+    @Nullable
+    private static byte[] transformToByteArray(@NonNull final PersistableBundle extras) {
+        Objects.requireNonNull(extras);
+        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
+            new PersistableBundle(extras).writeToStream(baos);
+            return baos.toByteArray();
+        } catch (IOException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Convert byte[] into Bundle.
+     */
+    @Nullable
+    private Bundle transformToBundle(@Nullable final byte[] extras) {
+        if (extras == null) {
+            return null;
+        }
+        Objects.requireNonNull(extras);
+        try (ByteArrayInputStream bais = new ByteArrayInputStream(extras)) {
+            final Bundle ret = new Bundle();
+            ret.putAll(PersistableBundle.readFromStream(bais));
+            return ret;
+        } catch (IOException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Convert byte[] into PersistableBundle.
+     */
+    @Nullable
+    private PersistableBundle transformToPersistableBundle(@Nullable final byte[] extras) {
+        if (extras == null) {
+            return null;
+        }
+        try (ByteArrayInputStream bais = new ByteArrayInputStream(extras)) {
+            return PersistableBundle.readFromStream(bais);
+        } catch (IOException e) {
+            return null;
+        }
+    }
+
+    private static long[] flattenFlags(@ShortcutInfo.ShortcutFlags final int flags) {
+        final List<Integer> flattenedFlags = new ArrayList<>();
+        flattenedFlags.add(0);
+        for (int i = 0; i < 31; i++) {
+            final int mask = 1 << i;
+            if ((flags & mask) != 0) {
+                flattenedFlags.add(mask);
+            }
+        }
+        return flattenedFlags.stream().mapToLong(i -> i).toArray();
+    }
+
+    private static int parseFlags(final long[] flags) {
+        return (int) Arrays.stream(flags).reduce((p, v) -> p | v).getAsLong();
+    }
+
+    @NonNull
+    private static Person[] parsePerson(@Nullable final GenericDocument[] persons) {
+        return persons == null ? new Person[0] : Arrays.stream(persons).map(it ->
+                ((AppSearchPerson) it).toPerson()).toArray(Person[]::new);
+    }
+}
diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl
index 9a73be9..f72288c 100644
--- a/core/java/android/content/pm/IPackageInstallerSession.aidl
+++ b/core/java/android/content/pm/IPackageInstallerSession.aidl
@@ -35,7 +35,7 @@
     void write(String name, long offsetBytes, long lengthBytes, in ParcelFileDescriptor fd);
     void stageViaHardLink(String target);
 
-    void addChecksums(String name, in Checksum[] checksums);
+    void setChecksums(String name, in Checksum[] checksums, in byte[] signature);
 
     void removeSplit(String splitName);
 
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 01d4c280..248be0f 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1247,12 +1247,15 @@
         }
 
         /**
-         * Adds installer-provided checksums for the APK file in session.
+         * Sets installer-provided checksums for the APK file in session.
          *
          * @param name      previously written as part of this session.
          *                  {@link #openWrite}
          * @param checksums installer intends to make available via
          *                  {@link PackageManager#requestChecksums}.
+         * @param signature PKCS#7 detached signature bytes over serialized checksums to enable
+         *                  fs-verity for the checksums or null if fs-verity should not be enabled.
+         *                  @see <a href="https://www.kernel.org/doc/html/latest/filesystems/fsverity.html#built-in-signature-verification">fs-verity</a>
          * @throws SecurityException if called after the session has been
          *                           committed or abandoned.
          * @throws IllegalStateException if checksums for this file have already been added.
@@ -1262,13 +1265,14 @@
          *              in {@link PackageManager#requestChecksums}.
          */
         @Deprecated
-        public void addChecksums(@NonNull String name, @NonNull List<Checksum> checksums)
-                throws IOException {
+        public void setChecksums(@NonNull String name, @NonNull List<Checksum> checksums,
+                @Nullable byte[] signature) throws IOException {
             Objects.requireNonNull(name);
             Objects.requireNonNull(checksums);
 
             try {
-                mSession.addChecksums(name, checksums.toArray(new Checksum[checksums.size()]));
+                mSession.setChecksums(name, checksums.toArray(new Checksum[checksums.size()]),
+                        signature);
             } catch (RuntimeException e) {
                 ExceptionUtils.maybeUnwrapIOException(e);
                 throw e;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 17c4d25..03d4d5e 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3513,6 +3513,17 @@
     public static final String FEATURE_TUNER = "android.hardware.tv.tuner";
 
     /**
+     * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device supports a enabling/disabling sensor privacy for
+     * camera. When sensory privacy for the camera is enabled no camera data is send to clients,
+     * e.g. the view finder in a camera app would appear blank.
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_CAMERA_TOGGLE = "android.hardware.camera.toggle";
+
+    /**
      * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device has
      * the necessary changes to support app enumeration.
      *
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index da75fba..522f4ca 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -2191,7 +2191,7 @@
         dest.writeString8(mIconUri);
     }
 
-    public static final @android.annotation.NonNull Creator<ShortcutInfo> CREATOR =
+    public static final @NonNull Creator<ShortcutInfo> CREATOR =
             new Creator<ShortcutInfo>() {
                 public ShortcutInfo createFromParcel(Parcel source) {
                     return new ShortcutInfo(source);
diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
index 056af77..f8fd4a5 100644
--- a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
+++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
@@ -295,8 +295,10 @@
             pi.applicationInfo.publicSourceDir = apexFile.getPath();
             if (apexInfo.isFactory) {
                 pi.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+                pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
             } else {
                 pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;
+                pi.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
             }
             if (apexInfo.isActive) {
                 pi.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index f7c4c2c..ec6c233 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -881,7 +881,11 @@
         }
     }
 
-    static int getMaxLengthValuesArray(Sensor sensor, int sdkLevel) {
+    /**
+     * Return sensor's maximum length of values array
+     * @hide
+     */
+    public static int getMaxLengthValuesArray(Sensor sensor, int sdkLevel) {
         // RotationVector length has changed to 3 to 5 for API level 18
         // Set it to 3 for backward compatibility.
         if (sensor.mType == Sensor.TYPE_ROTATION_VECTOR
diff --git a/core/java/android/hardware/input/InputDeviceSensorManager.java b/core/java/android/hardware/input/InputDeviceSensorManager.java
index 56c2cdd..89db857 100644
--- a/core/java/android/hardware/input/InputDeviceSensorManager.java
+++ b/core/java/android/hardware/input/InputDeviceSensorManager.java
@@ -25,6 +25,7 @@
 import android.hardware.SensorEventListener;
 import android.hardware.SensorManager;
 import android.hardware.TriggerEventListener;
+import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
@@ -32,6 +33,7 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.view.InputDevice;
 
 import com.android.internal.annotations.GuardedBy;
@@ -65,8 +67,8 @@
     @GuardedBy("mInputSensorLock")
     private final ArrayList<InputSensorEventListenerDelegate> mInputSensorEventListeners =
             new ArrayList<InputSensorEventListenerDelegate>();
-    private HandlerThread mSensorThread = null;
-    private Handler mSensorHandler = null;
+    private final HandlerThread mSensorThread;
+    private final Handler mSensorHandler;
 
     public InputDeviceSensorManager(InputManager inputManager) {
         mInputManager = inputManager;
@@ -125,9 +127,7 @@
     @Override
     public void onInputDeviceChanged(int deviceId) {
         synchronized (mInputSensorLock) {
-            if (mSensors.containsKey(deviceId)) {
-                mSensors.remove(deviceId);
-            }
+            mSensors.remove(deviceId);
             updateInputDeviceSensorInfoLocked(deviceId);
         }
     }
@@ -196,16 +196,21 @@
                     + " timestamp=" + timestamp + " sensorType=" + sensorType);
         }
         synchronized (mInputSensorLock) {
-            SensorEvent event = createSensorEvent(
-                    InputDevice.getDevice(deviceId), sensorType, accuracy, timestamp, values);
-            if (event == null) {
-                Slog.wtf(TAG, "Failed to create SensorEvent.");
-                return;
-            }
+            Sensor sensor = getInputDeviceSensorLocked(deviceId, sensorType);
             for (int i = 0; i < mInputSensorEventListeners.size(); i++) {
                 InputSensorEventListenerDelegate listener =
                         mInputSensorEventListeners.get(i);
                 if (listener.hasSensorRegistered(deviceId, sensorType)) {
+                    SensorEvent event = listener.getSensorEvent(sensor);
+                    if (event == null) {
+                        Slog.wtf(TAG, "Failed to get SensorEvent.");
+                        return;
+                    }
+                    event.sensor = sensor;
+                    event.accuracy = accuracy;
+                    event.timestamp = timestamp;
+                    System.arraycopy(values, 0, event.values, 0, event.values.length);
+                    // Call listener for sensor changed
                     listener.sendSensorChanged(event);
                 }
             }
@@ -249,15 +254,19 @@
         private final SensorEventListener mListener;
         private final int mDelayUs;
         private final int mMaxBatchReportLatencyUs;
+        // List of sensors being listened to
         private List<Sensor> mSensors = new ArrayList<Sensor>();
+        // Sensor event array by sensor type, preallocate sensor events for each sensor of listener
+        // to avoid allocation and garbage collection for each listener callback.
+        private final SparseArray<SensorEvent> mSensorEvents = new SparseArray<SensorEvent>();
 
         InputSensorEventListenerDelegate(SensorEventListener listener, Sensor sensor,
                 int delayUs, int maxBatchReportLatencyUs, Handler handler) {
             super(handler != null ? handler.getLooper() : Looper.myLooper());
             mListener = listener;
-            mSensors.add(sensor);
             mDelayUs = delayUs;
             mMaxBatchReportLatencyUs = maxBatchReportLatencyUs;
+            addSensor(sensor);
         }
 
         public List<Sensor> getSensors() {
@@ -276,10 +285,12 @@
             // and the sensor list is cleared.
             if (sensor == null) {
                 mSensors.clear();
+                mSensorEvents.clear();
             }
             for (Sensor s : mSensors) {
                 if (sensorEquals(s, sensor)) {
                     mSensors.remove(sensor);
+                    mSensorEvents.remove(sensor.getType());
                 }
             }
         }
@@ -295,6 +306,10 @@
                 }
             }
             mSensors.add(sensor);
+            final int vecLength = sensor.getMaxLengthValuesArray(sensor, Build.VERSION.SDK_INT);
+            SensorEvent event = new SensorEvent(sensor, SensorManager.SENSOR_STATUS_NO_CONTACT,
+                    0 /* timestamp */, new float[vecLength]);
+            mSensorEvents.put(sensor.getType(), event);
         }
 
         /**
@@ -320,6 +335,13 @@
         }
 
         /**
+         * Get SensorEvent object for input device, with specified sensor.
+         */
+        private SensorEvent getSensorEvent(@NonNull Sensor sensor) {
+            return mSensorEvents.get(sensor.getType());
+        }
+
+        /**
          * Send sensor changed message
          */
         public void sendSensorChanged(SensorEvent event) {
@@ -360,26 +382,6 @@
     }
 
     /**
-     * Create SensorEvent object for input device, with specified device ID, sensor Type,
-     * sensor event timestamp, accuracy, and sensor values.
-     */
-    private SensorEvent createSensorEvent(InputDevice inputDevice, int sensorType, int accuracy,
-            long timestamp, float[] values) {
-        synchronized (mInputSensorLock) {
-            Sensor sensor = getInputDeviceSensorLocked(inputDevice.getId(), sensorType);
-            if (sensor == null) {
-                Slog.wtf(TAG, "Can't get sensor type " + sensorType + " for input device "
-                        + inputDevice);
-            }
-            SensorEvent event = new SensorEvent(sensor, accuracy, timestamp, values);
-            if (event == null) {
-                Slog.wtf(TAG, "Failed to create SensorEvent.");
-            }
-            return event;
-        }
-    }
-
-    /**
      * Return the default sensor object for input device, for specific sensor type.
      */
     private Sensor getSensorForInputDevice(int deviceId, int type) {
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 930950e..899af5a 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -72,7 +72,6 @@
 
 import libcore.net.event.NetworkEventDispatcher;
 
-import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.UncheckedIOException;
 import java.lang.annotation.Retention;
@@ -1958,6 +1957,12 @@
         return k;
     }
 
+    // Construct an invalid fd.
+    private ParcelFileDescriptor createInvalidFd() {
+        final int invalidFd = -1;
+        return ParcelFileDescriptor.adoptFd(invalidFd);
+    }
+
     /**
      * Request that keepalives be started on a IPsec NAT-T socket.
      *
@@ -1988,7 +1993,7 @@
         } catch (IOException ignored) {
             // Construct an invalid fd, so that if the user later calls start(), it will fail with
             // ERROR_INVALID_SOCKET.
-            dup = new ParcelFileDescriptor(new FileDescriptor());
+            dup = createInvalidFd();
         }
         return new NattSocketKeepalive(mService, network, dup, socket.getResourceId(), source,
                 destination, executor, callback);
@@ -2030,7 +2035,7 @@
         } catch (IOException ignored) {
             // Construct an invalid fd, so that if the user later calls start(), it will fail with
             // ERROR_INVALID_SOCKET.
-            dup = new ParcelFileDescriptor(new FileDescriptor());
+            dup = createInvalidFd();
         }
         return new NattSocketKeepalive(mService, network, dup,
                 INVALID_RESOURCE_ID /* Unused */, source, destination, executor, callback);
@@ -2067,7 +2072,7 @@
         } catch (UncheckedIOException ignored) {
             // Construct an invalid fd, so that if the user later calls start(), it will fail with
             // ERROR_INVALID_SOCKET.
-            dup = new ParcelFileDescriptor(new FileDescriptor());
+            dup = createInvalidFd();
         }
         return new TcpSocketKeepalive(mService, network, dup, executor, callback);
     }
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index c029dea..cad0db2 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -160,7 +160,7 @@
 
     /** @hide */
     public static final int FOREGROUND_THRESHOLD_STATE =
-            ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+            ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
 
     /**
      * {@link Intent} extra that indicates which {@link NetworkTemplate} rule it
diff --git a/core/java/android/net/metrics/IpConnectivityLog.java b/core/java/android/net/metrics/IpConnectivityLog.java
index 58ea915..bb91f89 100644
--- a/core/java/android/net/metrics/IpConnectivityLog.java
+++ b/core/java/android/net/metrics/IpConnectivityLog.java
@@ -137,7 +137,7 @@
      * @return true if the event was successfully logged.
      */
     public boolean log(@NonNull Network network, @NonNull int[] transports, @NonNull Event data) {
-        return log(network.netId, transports, data);
+        return log(network.getNetId(), transports, data);
     }
 
     /**
diff --git a/core/java/android/net/vcn/IVcnManagementService.aidl b/core/java/android/net/vcn/IVcnManagementService.aidl
index 04b585c..80ac64b 100644
--- a/core/java/android/net/vcn/IVcnManagementService.aidl
+++ b/core/java/android/net/vcn/IVcnManagementService.aidl
@@ -16,6 +16,7 @@
 
 package android.net.vcn;
 
+import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
 import android.net.vcn.VcnConfig;
 import android.os.ParcelUuid;
 
@@ -25,4 +26,7 @@
 interface IVcnManagementService {
     void setVcnConfig(in ParcelUuid subscriptionGroup, in VcnConfig config, in String opPkgName);
     void clearVcnConfig(in ParcelUuid subscriptionGroup);
+
+    void addVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener);
+    void removeVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener);
 }
diff --git a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl b/core/java/android/net/vcn/IVcnUnderlyingNetworkPolicyListener.aidl
similarity index 64%
rename from media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl
rename to core/java/android/net/vcn/IVcnUnderlyingNetworkPolicyListener.aidl
index edf96dd..f8ae492 100644
--- a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl
+++ b/core/java/android/net/vcn/IVcnUnderlyingNetworkPolicyListener.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.
@@ -14,17 +14,9 @@
  * limitations under the License.
  */
 
-package android.media.tv.tunerresourcemanager;
+package android.net.vcn;
 
-/**
- * Simple container of the FrontendInfo struct defined in the TunerHAL 1.0 interface.
- *
- * @hide
- */
-parcelable TunerFrontendInfo {
-    int handle;
-
-    int frontendType;
-
-    int exclusiveGroupId;
-}
+/** @hide */
+interface IVcnUnderlyingNetworkPolicyListener {
+    void onPolicyChanged();
+}
\ No newline at end of file
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index 039360a..d531cdb 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -15,8 +15,6 @@
  */
 package android.net.vcn;
 
-import static android.net.NetworkCapabilities.NetCapability;
-
 import static com.android.internal.annotations.VisibleForTesting.Visibility;
 
 import android.annotation.IntRange;
@@ -233,7 +231,7 @@
      *
      * @param capability the capability to check for
      */
-    public boolean hasExposedCapability(@NetCapability int capability) {
+    public boolean hasExposedCapability(int capability) {
         checkValidCapability(capability);
 
         return mExposedCapabilities.contains(capability);
@@ -254,7 +252,7 @@
      *
      * @param capability the capability to check for
      */
-    public boolean requiresUnderlyingCapability(@NetCapability int capability) {
+    public boolean requiresUnderlyingCapability(int capability) {
         checkValidCapability(capability);
 
         return mUnderlyingCapabilities.contains(capability);
@@ -341,7 +339,7 @@
          * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway
          *     Connection
          */
-        public Builder addExposedCapability(@NetCapability int exposedCapability) {
+        public Builder addExposedCapability(int exposedCapability) {
             checkValidCapability(exposedCapability);
 
             mExposedCapabilities.add(exposedCapability);
@@ -357,7 +355,7 @@
          * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway
          *     Connection
          */
-        public Builder removeExposedCapability(@NetCapability int exposedCapability) {
+        public Builder removeExposedCapability(int exposedCapability) {
             checkValidCapability(exposedCapability);
 
             mExposedCapabilities.remove(exposedCapability);
@@ -373,7 +371,7 @@
          * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying
          *     networks
          */
-        public Builder addRequiredUnderlyingCapability(@NetCapability int underlyingCapability) {
+        public Builder addRequiredUnderlyingCapability(int underlyingCapability) {
             checkValidCapability(underlyingCapability);
 
             mUnderlyingCapabilities.add(underlyingCapability);
@@ -393,7 +391,7 @@
          * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying
          *     networks
          */
-        public Builder removeRequiredUnderlyingCapability(@NetCapability int underlyingCapability) {
+        public Builder removeRequiredUnderlyingCapability(int underlyingCapability) {
             checkValidCapability(underlyingCapability);
 
             mUnderlyingCapabilities.remove(underlyingCapability);
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index b881a339..2ccdc26 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -25,7 +25,12 @@
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
 
 /**
  * VcnManager publishes APIs for applications to configure and manage Virtual Carrier Networks.
@@ -60,6 +65,11 @@
 public final class VcnManager {
     @NonNull private static final String TAG = VcnManager.class.getSimpleName();
 
+    @VisibleForTesting
+    public static final Map<
+                    VcnUnderlyingNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder>
+            REGISTERED_POLICY_LISTENERS = new ConcurrentHashMap<>();
+
     @NonNull private final Context mContext;
     @NonNull private final IVcnManagementService mService;
 
@@ -136,4 +146,101 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    // TODO: make VcnUnderlyingNetworkPolicyListener @SystemApi
+    /**
+     * VcnUnderlyingNetworkPolicyListener is the interface through which internal system components
+     * can register to receive updates for VCN-underlying Network policies from the System Server.
+     *
+     * @hide
+     */
+    public interface VcnUnderlyingNetworkPolicyListener {
+        /**
+         * Notifies the implementation that the VCN's underlying Network policy has changed.
+         *
+         * <p>After receiving this callback, implementations MUST poll VcnManager for the updated
+         * VcnUnderlyingNetworkPolicy via VcnManager#getUnderlyingNetworkPolicy.
+         */
+        void onPolicyChanged();
+    }
+
+    /**
+     * Add a listener for VCN-underlying network policy updates.
+     *
+     * @param executor the Executor that will be used for invoking all calls to the specified
+     *     Listener
+     * @param listener the VcnUnderlyingNetworkPolicyListener to be added
+     * @throws SecurityException if the caller does not have permission NETWORK_FACTORY
+     * @throws IllegalArgumentException if the specified VcnUnderlyingNetworkPolicyListener is
+     *     already registered
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+    public void addVcnUnderlyingNetworkPolicyListener(
+            @NonNull Executor executor, @NonNull VcnUnderlyingNetworkPolicyListener listener) {
+        requireNonNull(executor, "executor must not be null");
+        requireNonNull(listener, "listener must not be null");
+
+        VcnUnderlyingNetworkPolicyListenerBinder binder =
+                new VcnUnderlyingNetworkPolicyListenerBinder(executor, listener);
+        if (REGISTERED_POLICY_LISTENERS.putIfAbsent(listener, binder) != null) {
+            throw new IllegalArgumentException(
+                    "Attempting to add a listener that is already in use");
+        }
+
+        try {
+            mService.addVcnUnderlyingNetworkPolicyListener(binder);
+        } catch (RemoteException e) {
+            REGISTERED_POLICY_LISTENERS.remove(listener);
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Remove the specified VcnUnderlyingNetworkPolicyListener from VcnManager.
+     *
+     * <p>If the specified listener is not currently registered, this is a no-op.
+     *
+     * @param listener the VcnUnderlyingNetworkPolicyListener that will be removed
+     * @hide
+     */
+    public void removeVcnUnderlyingNetworkPolicyListener(
+            @NonNull VcnUnderlyingNetworkPolicyListener listener) {
+        requireNonNull(listener, "listener must not be null");
+
+        VcnUnderlyingNetworkPolicyListenerBinder binder =
+                REGISTERED_POLICY_LISTENERS.remove(listener);
+        if (binder == null) {
+            return;
+        }
+
+        try {
+            mService.removeVcnUnderlyingNetworkPolicyListener(binder);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Binder wrapper for added VcnUnderlyingNetworkPolicyListeners to receive signals from System
+     * Server.
+     *
+     * @hide
+     */
+    private static class VcnUnderlyingNetworkPolicyListenerBinder
+            extends IVcnUnderlyingNetworkPolicyListener.Stub {
+        @NonNull private final Executor mExecutor;
+        @NonNull private final VcnUnderlyingNetworkPolicyListener mListener;
+
+        private VcnUnderlyingNetworkPolicyListenerBinder(
+                Executor executor, VcnUnderlyingNetworkPolicyListener listener) {
+            mExecutor = executor;
+            mListener = listener;
+        }
+
+        @Override
+        public void onPolicyChanged() {
+            mExecutor.execute(() -> mListener.onPolicyChanged());
+        }
+    }
 }
diff --git a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.aidl
similarity index 64%
copy from media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl
copy to core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.aidl
index edf96dd..6cb6ee6 100644
--- a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl
+++ b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.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.
@@ -14,17 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.tv.tunerresourcemanager;
+package android.net.vcn;
 
-/**
- * Simple container of the FrontendInfo struct defined in the TunerHAL 1.0 interface.
- *
- * @hide
- */
-parcelable TunerFrontendInfo {
-    int handle;
-
-    int frontendType;
-
-    int exclusiveGroupId;
-}
+/** @hide */
+parcelable VcnUnderlyingNetworkPolicy;
diff --git a/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java
new file mode 100644
index 0000000..dd7c86d8
--- /dev/null
+++ b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java
@@ -0,0 +1,110 @@
+/*
+ * 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.net.vcn;
+
+import android.annotation.NonNull;
+import android.net.NetworkCapabilities;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * VcnUnderlyingNetworkPolicy represents the Network policy for a VCN-managed Network.
+ *
+ * <p>Transports that are bringing up networks capable of acting as a VCN's underlying network
+ * should query for policy state upon major capability changes (e.g. changing of TRUSTED bit), and
+ * when prompted by VcnManagementService via VcnUnderlyingNetworkPolicyListener.
+ *
+ * @hide
+ */
+public final class VcnUnderlyingNetworkPolicy implements Parcelable {
+    private final boolean mIsTearDownRequested;
+    private final NetworkCapabilities mMergedNetworkCapabilities;
+
+    /**
+     * Constructs a VcnUnderlyingNetworkPolicy with the specified parameters.
+     *
+     * @hide
+     */
+    public VcnUnderlyingNetworkPolicy(
+            boolean isTearDownRequested, @NonNull NetworkCapabilities mergedNetworkCapabilities) {
+        Objects.requireNonNull(
+                mergedNetworkCapabilities, "mergedNetworkCapabilities must be nonnull");
+
+        mIsTearDownRequested = isTearDownRequested;
+        mMergedNetworkCapabilities = mergedNetworkCapabilities;
+    }
+
+    /**
+     * Returns whether this Carrier VCN policy policy indicates that the underlying Network should
+     * be torn down.
+     */
+    public boolean isTeardownRequested() {
+        return mIsTearDownRequested;
+    }
+
+    /**
+     * Returns the NetworkCapabilities with Carrier VCN policy bits merged into the provided
+     * capabilities.
+     */
+    @NonNull
+    public NetworkCapabilities getMergedNetworkCapabilities() {
+        return mMergedNetworkCapabilities;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mIsTearDownRequested, mMergedNetworkCapabilities);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof VcnUnderlyingNetworkPolicy)) return false;
+        final VcnUnderlyingNetworkPolicy that = (VcnUnderlyingNetworkPolicy) o;
+
+        return mIsTearDownRequested == that.mIsTearDownRequested
+                && mMergedNetworkCapabilities.equals(that.mMergedNetworkCapabilities);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeBoolean(mIsTearDownRequested);
+        dest.writeParcelable(mMergedNetworkCapabilities, flags);
+    }
+
+    /** Implement the Parcelable interface */
+    public static final @NonNull Creator<VcnUnderlyingNetworkPolicy> CREATOR =
+            new Creator<VcnUnderlyingNetworkPolicy>() {
+                public VcnUnderlyingNetworkPolicy createFromParcel(Parcel in) {
+                    return new VcnUnderlyingNetworkPolicy(
+                            in.readBoolean(), in.readParcelable(null));
+                }
+
+                public VcnUnderlyingNetworkPolicy[] newArray(int size) {
+                    return new VcnUnderlyingNetworkPolicy[size];
+                }
+            };
+}
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index 33736d3..305c686 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -22,6 +22,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.SuppressAutoDoc;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.app.ActivityManager;
@@ -40,12 +41,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.concurrent.Executor;
 
-/**
- * Class that provides a privileged API to capture and consume bugreports.
- *
- * @hide
- */
-@SystemApi
+/** Class that provides a privileged API to capture and consume bugreports. */
 @SystemService(Context.BUGREPORT_SERVICE)
 public final class BugreportManager {
 
@@ -60,28 +56,30 @@
         mBinder = binder;
     }
 
-    /**
-     * An interface describing the callback for bugreport progress and status.
-     */
+    /** An interface describing the callback for bugreport progress and status. */
     public abstract static class BugreportCallback {
-        /** @hide */
+        /**
+         * Possible error codes taking a bugreport can encounter.
+         *
+         * @hide
+         */
         @Retention(RetentionPolicy.SOURCE)
-        @IntDef(prefix = { "BUGREPORT_ERROR_" }, value = {
-                BUGREPORT_ERROR_INVALID_INPUT,
-                BUGREPORT_ERROR_RUNTIME,
-                BUGREPORT_ERROR_USER_DENIED_CONSENT,
-                BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT,
-                BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS
-        })
-
-        /** Possible error codes taking a bugreport can encounter */
+        @IntDef(
+                prefix = {"BUGREPORT_ERROR_"},
+                value = {
+                    BUGREPORT_ERROR_INVALID_INPUT,
+                    BUGREPORT_ERROR_RUNTIME,
+                    BUGREPORT_ERROR_USER_DENIED_CONSENT,
+                    BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT,
+                    BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS
+                })
         public @interface BugreportErrorCode {}
 
         /** The input options were invalid */
         public static final int BUGREPORT_ERROR_INVALID_INPUT =
                 IDumpstateListener.BUGREPORT_ERROR_INVALID_INPUT;
 
-        /** A runtime error occured */
+        /** A runtime error occurred */
         public static final int BUGREPORT_ERROR_RUNTIME =
                 IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR;
 
@@ -99,6 +97,7 @@
 
         /**
          * Called when there is a progress update.
+         *
          * @param progress the progress in [0.0, 100.0]
          */
         public void onProgress(@FloatRange(from = 0f, to = 100f) float progress) {}
@@ -113,14 +112,12 @@
          * out, but the bugreport could be available in the internal directory of dumpstate for
          * manual retrieval.
          *
-         * <p> If {@code BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS} is passed, then the
-         * caller should try later, as only one bugreport can be in progress at a time.
+         * <p>If {@code BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS} is passed, then the caller
+         * should try later, as only one bugreport can be in progress at a time.
          */
         public void onError(@BugreportErrorCode int errorCode) {}
 
-        /**
-         * Called when taking bugreport finishes successfully.
-         */
+        /** Called when taking bugreport finishes successfully. */
         public void onFinished() {}
 
         /**
@@ -137,20 +134,23 @@
      * seconds to return in the worst case. {@code callback} will receive progress and status
      * updates.
      *
-     * <p>The bugreport artifacts will be copied over to the given file descriptors only if the
-     * user consents to sharing with the calling app.
+     * <p>The bugreport artifacts will be copied over to the given file descriptors only if the user
+     * consents to sharing with the calling app.
      *
      * <p>{@link BugreportManager} takes ownership of {@code bugreportFd} and {@code screenshotFd}.
      *
-     * @param bugreportFd file to write the bugreport. This should be opened in write-only,
-     *     append mode.
-     * @param screenshotFd file to write the screenshot, if necessary. This should be opened
-     *     in write-only, append mode.
+     * @param bugreportFd file to write the bugreport. This should be opened in write-only, append
+     *     mode.
+     * @param screenshotFd file to write the screenshot, if necessary. This should be opened in
+     *     write-only, append mode.
      * @param params options that specify what kind of a bugreport should be taken
      * @param callback callback for progress and status updates
+     * @hide
      */
+    @SystemApi
     @RequiresPermission(android.Manifest.permission.DUMP)
-    public void startBugreport(@NonNull ParcelFileDescriptor bugreportFd,
+    public void startBugreport(
+            @NonNull ParcelFileDescriptor bugreportFd,
             @Nullable ParcelFileDescriptor screenshotFd,
             @NonNull BugreportParams params,
             @NonNull @CallbackExecutor Executor executor,
@@ -164,17 +164,21 @@
             boolean isScreenshotRequested = screenshotFd != null;
             if (screenshotFd == null) {
                 // Binder needs a valid File Descriptor to be passed
-                screenshotFd = ParcelFileDescriptor.open(new File("/dev/null"),
-                        ParcelFileDescriptor.MODE_READ_ONLY);
+                screenshotFd =
+                        ParcelFileDescriptor.open(
+                                new File("/dev/null"), ParcelFileDescriptor.MODE_READ_ONLY);
             }
-            DumpstateListener dsListener = new DumpstateListener(executor, callback,
-                    isScreenshotRequested);
+            DumpstateListener dsListener =
+                    new DumpstateListener(executor, callback, isScreenshotRequested);
             // Note: mBinder can get callingUid from the binder transaction.
-            mBinder.startBugreport(-1 /* callingUid */,
+            mBinder.startBugreport(
+                    -1 /* callingUid */,
                     mContext.getOpPackageName(),
                     bugreportFd.getFileDescriptor(),
                     screenshotFd.getFileDescriptor(),
-                    params.getMode(), dsListener, isScreenshotRequested);
+                    params.getMode(),
+                    dsListener,
+                    isScreenshotRequested);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         } catch (FileNotFoundException e) {
@@ -189,14 +193,60 @@
     }
 
     /**
+     * Starts a connectivity bugreport.
+     *
+     * <p>The connectivity bugreport is a specialized version of bugreport that only includes
+     * information specifically for debugging connectivity-related issues (e.g. telephony, wi-fi,
+     * and IP networking issues). It is intended primarily for use by OEMs and network providers
+     * such as mobile network operators. In addition to generally excluding information that isn't
+     * targeted to connectivity debugging, this type of bugreport excludes PII and sensitive
+     * information that isn't strictly necessary for connectivity debugging.
+     *
+     * <p>The calling app MUST have a context-specific reason for requesting a connectivity
+     * bugreport, such as detecting a connectivity-related issue. This API SHALL NOT be used to
+     * perform random sampling from a fleet of public end-user devices.
+     *
+     * <p>Calling this API will cause the system to ask the user for consent every single time. The
+     * bugreport artifacts will be copied over to the given file descriptors only if the user
+     * consents to sharing with the calling app.
+     *
+     * <p>This starts a bugreport in the background. However the call itself can take several
+     * seconds to return in the worst case. {@code callback} will receive progress and status
+     * updates.
+     *
+     * <p>Requires that the calling app has carrier privileges (see {@link
+     * android.telephony.TelephonyManager#hasCarrierPrivileges}) on any active subscription.
+     *
+     * @param bugreportFd file to write the bugreport. This should be opened in write-only, append
+     *     mode.
+     * @param callback callback for progress and status updates.
+     */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+    public void startConnectivityBugreport(
+            @NonNull ParcelFileDescriptor bugreportFd,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull BugreportCallback callback) {
+        startBugreport(
+                bugreportFd,
+                null /* screenshotFd */,
+                new BugreportParams(BugreportParams.BUGREPORT_MODE_TELEPHONY),
+                executor,
+                callback);
+    }
+
+    /**
      * Cancels the currently running bugreport.
      *
      * <p>Apps are only able to cancel their own bugreports. App A cannot cancel a bugreport started
      * by app B.
      *
+     * <p>Requires permission: {@link android.Manifest.permission#DUMP} or that the calling app has
+     * carrier privileges (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on
+     * any active subscription.
+     *
      * @throws SecurityException if trying to cancel another app's bugreport in progress
      */
-    @RequiresPermission(android.Manifest.permission.DUMP)
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     public void cancelBugreport() {
         try {
             mBinder.cancelBugreport(-1 /* callingUid */, mContext.getOpPackageName());
@@ -209,23 +259,26 @@
      * Requests a bugreport.
      *
      * <p>This requests the platform/system to take a bugreport and makes the final bugreport
-     * available to the user. The user may choose to share it with another app, but the bugreport
-     * is never given back directly to the app that requested it.
+     * available to the user. The user may choose to share it with another app, but the bugreport is
+     * never given back directly to the app that requested it.
      *
-     * @param params           {@link BugreportParams} that specify what kind of a bugreport should
-     *                         be taken, please note that not all kinds of bugreport allow for a
-     *                         progress notification
-     * @param shareTitle       title on the final share notification
+     * @param params {@link BugreportParams} that specify what kind of a bugreport should be taken,
+     *     please note that not all kinds of bugreport allow for a progress notification
+     * @param shareTitle title on the final share notification
      * @param shareDescription description on the final share notification
+     * @hide
      */
+    @SystemApi
     @RequiresPermission(android.Manifest.permission.DUMP)
-    public void requestBugreport(@NonNull BugreportParams params, @Nullable CharSequence shareTitle,
+    public void requestBugreport(
+            @NonNull BugreportParams params,
+            @Nullable CharSequence shareTitle,
             @Nullable CharSequence shareDescription) {
         try {
             String title = shareTitle == null ? null : shareTitle.toString();
             String description = shareDescription == null ? null : shareDescription.toString();
-            ActivityManager.getService().requestBugReportWithDescription(title, description,
-                    params.getMode());
+            ActivityManager.getService()
+                    .requestBugReportWithDescription(title, description, params.getMode());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -236,8 +289,8 @@
         private final BugreportCallback mCallback;
         private final boolean mIsScreenshotRequested;
 
-        DumpstateListener(Executor executor, BugreportCallback callback,
-                boolean isScreenshotRequested) {
+        DumpstateListener(
+                Executor executor, BugreportCallback callback, boolean isScreenshotRequested) {
             mExecutor = executor;
             mCallback = callback;
             mIsScreenshotRequested = isScreenshotRequested;
@@ -247,9 +300,7 @@
         public void onProgress(int progress) throws RemoteException {
             final long identity = Binder.clearCallingIdentity();
             try {
-                mExecutor.execute(() -> {
-                    mCallback.onProgress(progress);
-                });
+                mExecutor.execute(() -> mCallback.onProgress(progress));
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -259,9 +310,7 @@
         public void onError(int errorCode) throws RemoteException {
             final long identity = Binder.clearCallingIdentity();
             try {
-                mExecutor.execute(() -> {
-                    mCallback.onError(errorCode);
-                });
+                mExecutor.execute(() -> mCallback.onError(errorCode));
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -271,9 +320,7 @@
         public void onFinished() throws RemoteException {
             final long identity = Binder.clearCallingIdentity();
             try {
-                mExecutor.execute(() -> {
-                    mCallback.onFinished();
-                });
+                mExecutor.execute(() -> mCallback.onFinished());
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -288,20 +335,19 @@
             Handler mainThreadHandler = new Handler(Looper.getMainLooper());
             mainThreadHandler.post(
                     () -> {
-                        int message = success ? R.string.bugreport_screenshot_success_toast
-                                : R.string.bugreport_screenshot_failure_toast;
+                        int message =
+                                success
+                                        ? R.string.bugreport_screenshot_success_toast
+                                        : R.string.bugreport_screenshot_failure_toast;
                         Toast.makeText(mContext, message, Toast.LENGTH_LONG).show();
                     });
         }
 
         @Override
-        public void onUiIntensiveBugreportDumpsFinished()
-                throws RemoteException {
+        public void onUiIntensiveBugreportDumpsFinished() throws RemoteException {
             final long identity = Binder.clearCallingIdentity();
             try {
-                mExecutor.execute(() -> {
-                    mCallback.onEarlyReportFinished();
-                });
+                mExecutor.execute(() -> mCallback.onEarlyReportFinished());
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
diff --git a/core/java/android/os/CombinedVibrationEffect.java b/core/java/android/os/CombinedVibrationEffect.java
index 7ec7fff..869a727 100644
--- a/core/java/android/os/CombinedVibrationEffect.java
+++ b/core/java/android/os/CombinedVibrationEffect.java
@@ -87,8 +87,14 @@
     }
 
     /** @hide */
+    public abstract long getDuration();
+
+    /** @hide */
     public abstract void validate();
 
+    /** @hide */
+    public abstract boolean hasVibrator(int vibratorId);
+
     /**
      * A combination of haptic effects that should be played in multiple vibrators in sync.
      *
@@ -265,6 +271,11 @@
             return mEffect;
         }
 
+        @Override
+        public long getDuration() {
+            return mEffect.getDuration();
+        }
+
         /** @hide */
         @Override
         public void validate() {
@@ -272,12 +283,17 @@
         }
 
         @Override
+        public boolean hasVibrator(int vibratorId) {
+            return true;
+        }
+
+        @Override
         public boolean equals(Object o) {
             if (!(o instanceof Mono)) {
                 return false;
             }
             Mono other = (Mono) o;
-            return other.mEffect.equals(other.mEffect);
+            return mEffect.equals(other.mEffect);
         }
 
         @Override
@@ -345,6 +361,15 @@
             return mEffects;
         }
 
+        @Override
+        public long getDuration() {
+            long maxDuration = Long.MIN_VALUE;
+            for (int i = 0; i < mEffects.size(); i++) {
+                maxDuration = Math.max(maxDuration, mEffects.valueAt(i).getDuration());
+            }
+            return maxDuration;
+        }
+
         /** @hide */
         @Override
         public void validate() {
@@ -356,6 +381,11 @@
         }
 
         @Override
+        public boolean hasVibrator(int vibratorId) {
+            return mEffects.indexOfKey(vibratorId) >= 0;
+        }
+
+        @Override
         public boolean equals(Object o) {
             if (!(o instanceof Stereo)) {
                 return false;
@@ -445,6 +475,26 @@
             return mDelays;
         }
 
+        @Override
+        public long getDuration() {
+            long durations = 0;
+            final int effectCount = mEffects.size();
+            for (int i = 0; i < effectCount; i++) {
+                CombinedVibrationEffect effect = mEffects.get(i);
+                long duration = effect.getDuration();
+                if (duration < 0) {
+                    // If any duration is unknown, this combination duration is also unknown.
+                    return duration;
+                }
+                durations += duration;
+            }
+            long delays = 0;
+            for (int i = 0; i < effectCount; i++) {
+                delays += mDelays.get(i);
+            }
+            return durations + delays;
+        }
+
         /** @hide */
         @Override
         public void validate() {
@@ -452,13 +502,15 @@
                     "There should be at least one effect set for a combined effect");
             Preconditions.checkArgument(mEffects.size() == mDelays.size(),
                     "Effect and delays should have equal length");
-            for (long delay : mDelays) {
-                if (delay < 0) {
+            final int effectCount = mEffects.size();
+            for (int i = 0; i < effectCount; i++) {
+                if (mDelays.get(i) < 0) {
                     throw new IllegalArgumentException("Delays must all be >= 0"
                             + " (delays=" + mDelays + ")");
                 }
             }
-            for (CombinedVibrationEffect effect : mEffects) {
+            for (int i = 0; i < effectCount; i++) {
+                CombinedVibrationEffect effect = mEffects.get(i);
                 if (effect instanceof Sequential) {
                     throw new IllegalArgumentException(
                             "There should be no nested sequential effects in a combined effect");
@@ -468,6 +520,17 @@
         }
 
         @Override
+        public boolean hasVibrator(int vibratorId) {
+            final int effectCount = mEffects.size();
+            for (int i = 0; i < effectCount; i++) {
+                if (mEffects.get(i).hasVibrator(vibratorId)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
         public boolean equals(Object o) {
             if (!(o instanceof Sequential)) {
                 return false;
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 0326b72..a46af97 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -1442,11 +1442,13 @@
     public static FileDescriptor convertToModernFd(FileDescriptor fd) {
         try {
             Context context = AppGlobals.getInitialApplication();
-            File realFile = ParcelFileDescriptor.getFile(fd);
+            // /mnt/user paths are not accessible directly so convert to a /storage path
+            String filePath = Os.readlink("/proc/self/fd/" + fd.getInt$()).replace(
+                    "/mnt/user/" + UserHandle.myUserId(), "/storage");
+            File realFile = new File(filePath);
             String fileName = realFile.getName();
             boolean isCameraVideo = !fileName.startsWith(".") && fileName.endsWith(".mp4")
-                    && contains(CAMERA_DIR_LOWER_CASE, realFile.getAbsolutePath().toLowerCase(
-                                    Locale.ROOT));
+                    && contains(CAMERA_DIR_LOWER_CASE, filePath.toLowerCase(Locale.ROOT));
 
             if (!SystemProperties.getBoolean("sys.fuse.transcode_enabled", false)
                     || UserHandle.getAppId(Process.myUid()) == getMediaProviderAppId(context)
@@ -1471,7 +1473,7 @@
                 Log.i(TAG, "Failed to change to modern format dataSource for: " + realFile);
             }
         } catch (Exception e) {
-            Log.w(TAG, "Failed to change to modern format dataSource");
+            Log.w(TAG, "Failed to change to modern format dataSource", e);
         }
         return null;
     }
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index b951aca..814a248 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -612,12 +612,14 @@
      * @hide
      */
     public static class WakeData {
-        public WakeData(long wakeTime, @WakeReason int wakeReason) {
+        public WakeData(long wakeTime, @WakeReason int wakeReason, long sleepDuration) {
             this.wakeTime = wakeTime;
             this.wakeReason = wakeReason;
+            this.sleepDuration = sleepDuration;
         }
         public long wakeTime;
         public @WakeReason int wakeReason;
+        public long sleepDuration;
     }
 
     /**
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 086180e..b13be9f 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -2194,6 +2194,33 @@
         onVmPolicyViolation(new IncorrectContextUseViolation(message, originStack));
     }
 
+    /**
+     * A helper method to verify if the {@code context} is a UI context and throw
+     * {@link IncorrectContextUseViolation} if the {@code context} is not a UI context.
+     *
+     * @param context The context to verify if it is a UI context
+     * @param methodName The asserted method name
+     *
+     * @see Context#isUiContext()
+     * @see IncorrectContextUseViolation
+     *
+     * @hide
+     */
+    public static void assertUiContext(@NonNull Context context, @NonNull String methodName) {
+        if (vmIncorrectContextUseEnabled() && !context.isUiContext()) {
+            final String errorMessage = "Tried to access UI related API" + methodName
+                    + " from a non-UI Context:" + context;
+            final String message = "UI-related services, such as WindowManager, WallpaperService "
+                    + "or LayoutInflater should be accessed from Activity or other UI "
+                    + "Contexts. Use an Activity or a Context created with "
+                    + "Context#createWindowContext(int, Bundle), which are adjusted to "
+                    + "the configuration and visual bounds of an area on screen.";
+            final Exception exception = new IllegalAccessException(errorMessage);
+            StrictMode.onIncorrectContextUsed(message, exception);
+            Log.e(TAG, errorMessage + " " + message, exception);
+        }
+    }
+
     /** Assume locked until we hear otherwise */
     private static volatile boolean sUserKeyUnlocked = false;
 
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index c0b2ada..df3beb2 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -317,7 +317,7 @@
      */
     @TestApi
     public static VibrationEffect get(int effectId, boolean fallback) {
-        VibrationEffect effect = new Prebaked(effectId, fallback);
+        VibrationEffect effect = new Prebaked(effectId, fallback, EffectStrength.MEDIUM);
         effect.validate();
         return effect;
     }
@@ -792,22 +792,30 @@
     public static class Prebaked extends VibrationEffect implements Parcelable {
         private final int mEffectId;
         private final boolean mFallback;
-
-        private int mEffectStrength;
+        private final int mEffectStrength;
+        @Nullable
+        private final VibrationEffect mFallbackEffect;
 
         public Prebaked(Parcel in) {
-            this(in.readInt(), in.readByte() != 0, in.readInt());
+            mEffectId = in.readInt();
+            mFallback = in.readByte() != 0;
+            mEffectStrength = in.readInt();
+            mFallbackEffect = in.readParcelable(VibrationEffect.class.getClassLoader());
         }
 
-        public Prebaked(int effectId, boolean fallback) {
-            this(effectId, fallback, EffectStrength.MEDIUM);
-        }
-
-        /** @hide */
         public Prebaked(int effectId, boolean fallback, int effectStrength) {
             mEffectId = effectId;
             mFallback = fallback;
             mEffectStrength = effectStrength;
+            mFallbackEffect = null;
+        }
+
+        /** @hide */
+        public Prebaked(int effectId, int effectStrength, @NonNull VibrationEffect fallbackEffect) {
+            mEffectId = effectId;
+            mFallback = true;
+            mEffectStrength = effectStrength;
+            mFallbackEffect = fallbackEffect;
         }
 
         public int getId() {
@@ -829,26 +837,27 @@
 
         /** @hide */
         @Override
-        public VibrationEffect resolve(int defaultAmplitude) {
-            // Prebaked effects already have default amplitude set, so ignore this.
+        public Prebaked resolve(int defaultAmplitude) {
+            if (mFallbackEffect != null) {
+                VibrationEffect resolvedFallback = mFallbackEffect.resolve(defaultAmplitude);
+                if (!mFallbackEffect.equals(resolvedFallback)) {
+                    return new Prebaked(mEffectId, mEffectStrength, resolvedFallback);
+                }
+            }
             return this;
         }
 
         /** @hide */
         @Override
         public Prebaked scale(float scaleFactor) {
-            // Prebaked effects cannot be scaled, so ignore this.
-            return this;
-        }
-
-        /**
-         * Set the effect strength of the prebaked effect.
-         */
-        public void setEffectStrength(int strength) {
-            if (!isValidEffectStrength(strength)) {
-                throw new IllegalArgumentException("Invalid effect strength: " + strength);
+            if (mFallbackEffect != null) {
+                VibrationEffect scaledFallback = mFallbackEffect.scale(scaleFactor);
+                if (!mFallbackEffect.equals(scaledFallback)) {
+                    return new Prebaked(mEffectId, mEffectStrength, scaledFallback);
+                }
             }
-            mEffectStrength = strength;
+            // Prebaked effect strength cannot be scaled with this method.
+            return this;
         }
 
         /**
@@ -858,6 +867,16 @@
             return mEffectStrength;
         }
 
+        /**
+         * Return the fallback effect, if set.
+         *
+         * @hide
+         */
+        @Nullable
+        public VibrationEffect getFallbackEffect() {
+            return mFallbackEffect;
+        }
+
         private static boolean isValidEffectStrength(int strength) {
             switch (strength) {
                 case EffectStrength.LIGHT:
@@ -901,15 +920,13 @@
             VibrationEffect.Prebaked other = (VibrationEffect.Prebaked) o;
             return mEffectId == other.mEffectId
                 && mFallback == other.mFallback
-                && mEffectStrength == other.mEffectStrength;
+                && mEffectStrength == other.mEffectStrength
+                && Objects.equals(mFallbackEffect, other.mFallbackEffect);
         }
 
         @Override
         public int hashCode() {
-            int result = 17;
-            result += 37 * mEffectId;
-            result += 37 * mEffectStrength;
-            return result;
+            return Objects.hash(mEffectId, mFallback, mEffectStrength, mFallbackEffect);
         }
 
         @Override
@@ -917,6 +934,7 @@
             return "Prebaked{mEffectId=" + mEffectId
                 + ", mEffectStrength=" + mEffectStrength
                 + ", mFallback=" + mFallback
+                + ", mFallbackEffect=" + mFallbackEffect
                 + "}";
         }
 
@@ -927,6 +945,7 @@
             out.writeInt(mEffectId);
             out.writeByte((byte) (mFallback ? 1 : 0));
             out.writeInt(mEffectStrength);
+            out.writeParcelable(mFallbackEffect, flags);
         }
 
         public static final @NonNull Parcelable.Creator<Prebaked> CREATOR =
@@ -990,8 +1009,10 @@
                 // Just return this if there's no scaling to be done.
                 return this;
             }
+            final int primitiveCount = mPrimitiveEffects.size();
             List<Composition.PrimitiveEffect> scaledPrimitives = new ArrayList<>();
-            for (Composition.PrimitiveEffect primitive : mPrimitiveEffects) {
+            for (int i = 0; i < primitiveCount; i++) {
+                Composition.PrimitiveEffect primitive = mPrimitiveEffects.get(i);
                 scaledPrimitives.add(new Composition.PrimitiveEffect(
                         primitive.id, scale(primitive.scale, scaleFactor), primitive.delay));
             }
@@ -1001,11 +1022,12 @@
         /** @hide */
         @Override
         public void validate() {
-            for (Composition.PrimitiveEffect effect : mPrimitiveEffects) {
-                Composition.checkPrimitive(effect.id);
-                Preconditions.checkArgumentInRange(
-                        effect.scale, 0.0f, 1.0f, "scale");
-                Preconditions.checkArgumentNonNegative(effect.delay,
+            final int primitiveCount = mPrimitiveEffects.size();
+            for (int i = 0; i < primitiveCount; i++) {
+                Composition.PrimitiveEffect primitive = mPrimitiveEffects.get(i);
+                Composition.checkPrimitive(primitive.id);
+                Preconditions.checkArgumentInRange(primitive.scale, 0.0f, 1.0f, "scale");
+                Preconditions.checkArgumentNonNegative(primitive.delay,
                         "Primitive delay must be zero or positive");
             }
         }
diff --git a/core/java/android/os/incremental/IncrementalFileStorages.java b/core/java/android/os/incremental/IncrementalFileStorages.java
index 59292baa..9fdc72b 100644
--- a/core/java/android/os/incremental/IncrementalFileStorages.java
+++ b/core/java/android/os/incremental/IncrementalFileStorages.java
@@ -36,6 +36,7 @@
 import android.content.Context;
 import android.content.pm.DataLoaderParams;
 import android.content.pm.IDataLoaderStatusListener;
+import android.content.pm.IPackageLoadingProgressCallback;
 import android.content.pm.InstallationFileParcel;
 import android.text.TextUtils;
 
@@ -70,7 +71,8 @@
             @Nullable StorageHealthCheckParams healthCheckParams,
             @Nullable IStorageHealthListener healthListener,
             @NonNull List<InstallationFileParcel> addedFiles,
-            @NonNull PerUidReadTimeouts[] perUidReadTimeouts) throws IOException {
+            @NonNull PerUidReadTimeouts[] perUidReadTimeouts,
+            IPackageLoadingProgressCallback progressCallback) throws IOException {
         // TODO(b/136132412): validity check if session should not be incremental
         IncrementalManager incrementalManager = (IncrementalManager) context.getSystemService(
                 Context.INCREMENTAL_SERVICE);
@@ -95,7 +97,11 @@
                 throw new IOException("Unknown file location: " + file.location);
             }
         }
-
+        // Register progress loading callback after files have been added
+        if (progressCallback != null) {
+            incrementalManager.registerLoadingProgressCallback(stageDir.getAbsolutePath(),
+                    progressCallback);
+        }
         result.startLoading();
 
         return result;
@@ -180,6 +186,7 @@
 
         try {
             mDefaultStorage.unBind(mStageDir.getAbsolutePath());
+            mDefaultStorage.unregisterLoadingProgressListener();
         } catch (IOException ignored) {
         }
         mDefaultStorage = null;
diff --git a/core/java/android/os/storage/DiskInfo.java b/core/java/android/os/storage/DiskInfo.java
index 67317c7..d32928c 100644
--- a/core/java/android/os/storage/DiskInfo.java
+++ b/core/java/android/os/storage/DiskInfo.java
@@ -50,6 +50,8 @@
     public static final int FLAG_DEFAULT_PRIMARY = 1 << 1;
     public static final int FLAG_SD = 1 << 2;
     public static final int FLAG_USB = 1 << 3;
+    /** The FLAG_STUB_VISIBLE is set from vold, which gets the flag from outside (e.g., ChromeOS) */
+    public static final int FLAG_STUB_VISIBLE = 1 << 6;
 
     public final String id;
     @UnsupportedAppUsage
@@ -152,6 +154,10 @@
         return (flags & FLAG_USB) != 0;
     }
 
+    public boolean isStubVisible() {
+        return (flags & FLAG_STUB_VISIBLE) != 0;
+    }
+
     @Override
     public String toString() {
         final CharArrayWriter writer = new CharArrayWriter();
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index 99bdfd1..4669b20 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -195,4 +195,5 @@
     void abortChanges(in String message, boolean retry) = 87;
     void clearUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 88;
     void fixupAppDir(in String path) = 89;
+    void disableAppDataIsolation(in String pkgName, int pid, int userId) = 90;
 }
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index e599776..c28b59b 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -183,8 +183,9 @@
         }
 
         Map<String, List<OpUsage>> rawUsages = getOpUsages(ops);
+        Set<List<PackageAttribution>> proxyChains = getProxyChains(rawUsages.get(MICROPHONE));
         Map<PackageAttribution, CharSequence> packagesWithAttributionLabels =
-                getTrustedAttributions(rawUsages.get(MICROPHONE));
+                getTrustedAttributions(rawUsages.get(MICROPHONE), proxyChains);
 
         List<String> usedPermGroups = new ArrayList<>(rawUsages.keySet());
         for (int permGroupNum = 0; permGroupNum < usedPermGroups.size(); permGroupNum++) {
@@ -192,10 +193,14 @@
             String permGroup = usedPermGroups.get(permGroupNum);
 
             Map<PackageAttribution, CharSequence> pkgAttrLabels = packagesWithAttributionLabels;
+            Set<List<PackageAttribution>> proxies = proxyChains;
             if (!MICROPHONE.equals(permGroup)) {
                 pkgAttrLabels = new ArrayMap<>();
+                proxies = new ArraySet<>();
             }
-            removeDuplicates(rawUsages.get(permGroup), pkgAttrLabels.keySet());
+
+            List<OpUsage> permUsages = removeDuplicatesAndProxies(rawUsages.get(permGroup),
+                    pkgAttrLabels.keySet(), proxies);
 
             if (permGroup.equals(OPSTR_PHONE_CALL_MICROPHONE)) {
                 isPhone = true;
@@ -205,9 +210,8 @@
                 permGroup = CAMERA;
             }
 
-            int numUsages = rawUsages.get(permGroup).size();
-            for (int usageNum = 0; usageNum < numUsages; usageNum++) {
-                OpUsage usage = rawUsages.get(permGroup).get(usageNum);
+            for (int usageNum = 0; usageNum < permUsages.size(); usageNum++) {
+                OpUsage usage = permUsages.get(usageNum);
                 usages.add(new PermGroupUsage(usage.packageName, usage.uid, permGroup,
                         usage.lastAccessTime, usage.isRunning, isPhone,
                         packagesWithAttributionLabels.get(usage.toPackageAttr())));
@@ -278,7 +282,7 @@
                     AppOpsManager.OpEventProxyInfo proxy = attrOpEntry.getLastProxyInfo(opFlags);
                     if (proxy != null && proxy.getPackageName() != null) {
                         proxyUsage = new OpUsage(proxy.getPackageName(), proxy.getAttributionTag(),
-                                uid, lastAccessTime, isRunning, null);
+                                proxy.getUid(), lastAccessTime, isRunning, null);
                     }
 
                     String permGroupName = getGroupForOp(op);
@@ -323,17 +327,15 @@
      * trusted attribution label, if there is one
      */
     private ArrayMap<PackageAttribution, CharSequence> getTrustedAttributions(
-            List<OpUsage> usages) {
+            List<OpUsage> usages, Set<List<PackageAttribution>> proxyChains) {
         ArrayMap<PackageAttribution, CharSequence> attributions = new ArrayMap<>();
         if (usages == null) {
             return attributions;
         }
 
-        Set<List<PackageAttribution>> proxyChains = getProxyChains(usages);
         Map<PackageAttribution, CharSequence> trustedLabels =
                 getTrustedAttributionLabels(usages);
 
-
         for (List<PackageAttribution> chain : proxyChains) {
             // If this chain is empty, or has only one link, then do not show any special labels
             if (chain.size() <= 1) {
@@ -413,37 +415,24 @@
      * the chain has the previous one listed as a proxy usage.
      */
     private Set<List<PackageAttribution>> getProxyChains(List<OpUsage> usages) {
-        ArrayMap<PackageAttribution, List<PackageAttribution>> proxyChains = new ArrayMap<>();
+        if (usages == null) {
+            return new ArraySet<>();
+        }
+
+        ArrayMap<PackageAttribution, ArrayList<PackageAttribution>> proxyChains = new ArrayMap<>();
         // map of usages that still need to be removed, or added to a chain
         ArrayMap<PackageAttribution, OpUsage> remainingUsages = new ArrayMap<>();
         // map of usage.proxy -> usage, telling us if a usage is a proxy
         ArrayMap<PackageAttribution, PackageAttribution> proxies = new ArrayMap<>();
-        for (int i = 0; i < remainingUsages.size(); i++) {
+        for (int i = 0; i < usages.size(); i++) {
             OpUsage usage = usages.get(i);
             remainingUsages.put(usage.toPackageAttr(), usage);
             if (usage.proxy != null) {
                 proxies.put(usage.proxy.toPackageAttr(), usage.toPackageAttr());
             }
         }
-        // find and remove all one-link chains (that is, all proxied apps whose proxy is not
-        // included in the usage list), and apps that are neither proxy nor proxied.
-        for (int usageNum = 0; usageNum < usages.size(); usageNum++) {
-            OpUsage usage = usages.get(usageNum);
-            PackageAttribution usageAttr = usage.toPackageAttr();
-            if (usage.proxy == null) {
-                if (!proxies.containsKey(usageAttr)) {
-                    remainingUsages.remove(usageAttr);
-                }
-                continue;
-            }
 
-            PackageAttribution proxyAttr = usage.proxy.toPackageAttr();
-            if (!remainingUsages.containsKey(proxyAttr)) {
-                remainingUsages.remove(usageAttr);
-            }
-        }
-
-        // find all possible starting points for chains
+        // find all possible end points for chains
         List<PackageAttribution> keys = new ArrayList<>(remainingUsages.keySet());
         for (int usageNum = 0; usageNum < remainingUsages.size(); usageNum++) {
             OpUsage usage = remainingUsages.get(keys.get(usageNum));
@@ -451,16 +440,21 @@
                 continue;
             }
             PackageAttribution usageAttr = usage.toPackageAttr();
-            // If this usage has a proxy, but is not a proxy, it is the start of a chain.
+            // If this usage has a proxy, but is not a proxy, it is the end of a chain.
+            // If it has no proxy, and isn't a proxy, remove it.
             if (!proxies.containsKey(usageAttr) && usage.proxy != null) {
-                proxyChains.put(usageAttr, List.of(usageAttr));
+                ArrayList<PackageAttribution> proxyList = new ArrayList<>();
+                proxyList.add(usageAttr);
+                proxyChains.put(usageAttr, proxyList);
+            } else if (!proxies.containsKey(usageAttr) && usage.proxy == null) {
+                remainingUsages.remove(keys.get(usageNum));
             }
         }
 
-        // assemble the chains
+        // assemble the chains in reverse order, then invert them
         for (int numStart = 0; numStart < proxyChains.size(); numStart++) {
             PackageAttribution currPackageAttr = proxyChains.keyAt(numStart);
-            List<PackageAttribution> proxyChain = proxyChains.get(currPackageAttr);
+            ArrayList<PackageAttribution> proxyChain = proxyChains.get(currPackageAttr);
             OpUsage currentUsage = remainingUsages.get(currPackageAttr);
             if (currentUsage == null || proxyChain == null) {
                 continue;
@@ -484,6 +478,8 @@
 
                 proxyChain.add(currPackageAttr);
             }
+            // invert the lists, so the element without a proxy is first on the list
+            Collections.reverse(proxyChain);
         }
 
         return new ArraySet<>(proxyChains.values());
@@ -590,7 +586,7 @@
 
         CharSequence label = getAttributionLabel(usage);
         if (trustedMap.get(usage.packageName).equals(label)) {
-            toSetMap.put(usage.toPackageAttr(), label);
+            toSetMap.put(opUsage.toPackageAttr(), label);
         }
     }
 
@@ -619,34 +615,76 @@
         }
     }
 
-    private void removeDuplicates(List<OpUsage> rawUsages,
-            Set<PackageAttribution> specialAttributions) {
-        List<OpUsage> toRemove = new ArrayList<>();
+    /**
+     * If we have multiple usages of a
+     * @param rawUsages The list of all usages that we wish to
+     * @param specialAttributions A set of all usages that have a special label
+     * @param proxies A list of proxy chains- all links but the last on the chain should be removed,
+     *                if the last link has a special label
+     * @return A list of usages without duplicates or proxy usages.
+     */
+    private List<OpUsage> removeDuplicatesAndProxies(List<OpUsage> rawUsages,
+            Set<PackageAttribution> specialAttributions,
+            Set<List<PackageAttribution>> proxies) {
+        List<OpUsage> deDuped = new ArrayList<>();
         if (rawUsages == null) {
-            return;
+            return deDuped;
         }
 
-        for (int usageNum = 0; usageNum < rawUsages.size(); usageNum++) {
-            PackageAttribution usageAttr = rawUsages.get(usageNum).toPackageAttr();
-            // If this attribution has a special attribution, do not remove it
-            if (specialAttributions.contains(usageAttr)) {
+        List<PackageAttribution> toRemoveProxies = new ArrayList<>();
+        for (List<PackageAttribution> proxyList: proxies) {
+            PackageAttribution lastLink = proxyList.get(proxyList.size() - 1);
+            if (!specialAttributions.contains(lastLink)) {
                 continue;
             }
-
-            // Search the rest of the list for apps with the same uid. If there is one, mark this
-            // usage for removal.
-            for (int otherUsageNum = usageNum + 1; otherUsageNum < rawUsages.size();
-                    otherUsageNum++) {
-                if (rawUsages.get(otherUsageNum).uid == usageAttr.uid) {
-                    toRemove.add(rawUsages.get(usageNum));
-                    break;
+            for (int proxyNum = 0; proxyNum < proxyList.size(); proxyNum++) {
+                if (!proxyList.get(proxyNum).equals(lastLink)) {
+                    toRemoveProxies.add(proxyList.get(proxyNum));
                 }
             }
         }
 
-        for (int i = 0; i < toRemove.size(); i++) {
-            rawUsages.remove(toRemove.get(i));
+        for (int usageNum = 0; usageNum < rawUsages.size(); usageNum++) {
+            OpUsage usage = rawUsages.get(usageNum);
+
+            // If this attribution has a special attribution, do not remove it
+            if (specialAttributions.contains(usage.toPackageAttr())) {
+                deDuped.add(usage);
+            }
+
+            // If this attribution is a proxy, remove it
+            if (toRemoveProxies.contains(usage.toPackageAttr())) {
+                continue;
+            }
+
+
+            // Search the rest of the list for usages with the same UID. If this is the most recent
+            // usage for that uid, keep it. Otherwise, remove it
+            boolean isMostRecentForUid = true;
+            for (int otherUsageNum = 0; otherUsageNum < rawUsages.size(); otherUsageNum++) {
+                OpUsage otherUsage = rawUsages.get(otherUsageNum);
+                if (otherUsage.uid == usage.uid) {
+                    if (otherUsage.isRunning && !usage.isRunning) {
+                        isMostRecentForUid = false;
+                    } else if (usage.isRunning
+                            && otherUsage.lastAccessTime >= usage.lastAccessTime) {
+                        isMostRecentForUid = false;
+                    } else if (otherUsage.lastAccessTime >= usage.lastAccessTime) {
+                        isMostRecentForUid = false;
+                    }
+
+                    if (!isMostRecentForUid) {
+                        break;
+                    }
+                }
+            }
+
+            if (isMostRecentForUid) {
+                deDuped.add(usage);
+            }
         }
+
+        return deDuped;
     }
 
     private boolean isUserSensitive(String packageName, UserHandle user, String op) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 9b570b7..27ba72b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1018,6 +1018,20 @@
             "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
 
     /**
+     * Activity Action: Show settings to manage all SIM profiles.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_MANAGE_ALL_SUBSCRIPTIONS_SETTINGS =
+            "android.settings.MANAGE_ALL_SUBSCRIPTIONS_SETTINGS";
+
+    /**
      * Activity Action: Show screen for controlling which apps can draw on top of other apps.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you safeguard against this.
diff --git a/core/java/android/service/search/OWNERS b/core/java/android/service/search/OWNERS
new file mode 100644
index 0000000..92835c2
--- /dev/null
+++ b/core/java/android/service/search/OWNERS
@@ -0,0 +1,2 @@
+hyunyoungs@google.com
+sfufa@google.com
diff --git a/core/java/android/text/FontConfig.java b/core/java/android/text/FontConfig.java
index 1878d61..8492363 100644
--- a/core/java/android/text/FontConfig.java
+++ b/core/java/android/text/FontConfig.java
@@ -19,171 +19,268 @@
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
 import android.annotation.IntDef;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
+import android.graphics.fonts.FontStyle;
 import android.graphics.fonts.FontVariationAxis;
-import android.net.Uri;
 import android.os.Build;
+import android.os.LocaleList;
 
+import java.io.File;
 import java.lang.annotation.Retention;
+import java.util.List;
 
 
 /**
  * Font configuration descriptions for System fonts.
- * @hide
+ * @hide  // TODO Make this SystemApi.
  */
 public final class FontConfig {
-    private final @NonNull Family[] mFamilies;
-    private final @NonNull Alias[] mAliases;
+    private final @NonNull List<Family> mFamilies;
+    private final @NonNull List<Alias> mAliases;
 
-    public FontConfig(@NonNull Family[] families, @NonNull Alias[] aliases) {
+    /**
+     * Construct a SystemFontConfig instance.
+     *
+     * @param families a list of font families.
+     * @param aliases a list of aliases.
+     *
+     * @hide Only system server can create this instance and passed via IPC.
+     */
+    public FontConfig(@NonNull List<Family> families, @NonNull List<Alias> aliases) {
         mFamilies = families;
         mAliases = aliases;
     }
 
     /**
      * Returns the ordered list of families included in the system fonts.
+     *
+     * @return a list of font families.
      */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public @NonNull Family[] getFamilies() {
+    public @NonNull List<Family> getFontFamilies() {
         return mFamilies;
     }
 
     /**
      * Returns the list of aliases defined for the font families in the system fonts.
+     *
+     * @return a list of font families.
      */
-    public @NonNull Alias[] getAliases() {
+    public @NonNull List<Alias> getAliases() {
         return mAliases;
     }
 
     /**
-     * Class that holds information about a Font.
+     * Returns the ordered list of families included in the system fonts.
+     * @deprecated Use getFontFamilies instead.
+     */
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+    public @NonNull Family[] getFamilies() {
+        return mFamilies.toArray(new Family[0]);
+    }
+
+    /**
+     * A class represents single font entry in system font configuration.
      */
     public static final class Font {
-        private final @NonNull String mFontName;
-        private final int mTtcIndex;
-        private final @NonNull FontVariationAxis[] mAxes;
-        private final int mWeight;
-        private final boolean mIsItalic;
-        private Uri mUri;
-        private final String mFallbackFor;
+        private final @NonNull File mFilePath;
+        private final @Nullable File mOriginalPath;
+        private final @NonNull FontStyle mStyle;
+        private final @IntRange(from = 0) int mIndex;
+        private final @NonNull String mFontVariationSettings;
+        private final @Nullable String mFallback;
 
         /**
-         * @hide
+         * Construct a Font instance.
+         *
+         * @hide Only system server can create this instance and passed via IPC.
          */
-        public Font(@NonNull String fontName, int ttcIndex, @NonNull FontVariationAxis[] axes,
-                int weight, boolean isItalic, String fallbackFor) {
-            mFontName = fontName;
-            mTtcIndex = ttcIndex;
-            mAxes = axes;
-            mWeight = weight;
-            mIsItalic = isItalic;
-            mFallbackFor = fallbackFor;
+        public Font(@NonNull File filePath, @Nullable File originalPath, @NonNull FontStyle style,
+                @IntRange(from = 0) int index, @NonNull String fontVariationSettings,
+                @Nullable String fallback) {
+            mFilePath = filePath;
+            mOriginalPath = originalPath;
+            mStyle = style;
+            mIndex = index;
+            mFontVariationSettings = fontVariationSettings;
+            mFallback = fallback;
         }
 
         /**
-         * Returns the name associated by the system to this font.
+         * Returns a file to the font file.
+         *
+         * @return a font file.
          */
-        public @NonNull String getFontName() {
-            return mFontName;
+        public @NonNull File getFilePath() {
+            return mFilePath;
+        }
+
+        /**
+         * Returns an original font file in the system directory.
+         *
+         * If the font file is not updated, returns null.
+         *
+         * @return returns the original font file in the system if the font file is updated. Returns
+         *         null if the font file is not updated.
+         */
+        public @Nullable File getOriginalPath() {
+            return mOriginalPath;
+        }
+
+        /**
+         * Returns a font style.
+         *
+         * @return a font style.
+         */
+        public @NonNull FontStyle getStyle() {
+            return mStyle;
+        }
+
+        /**
+         * Returns a font index.
+         *
+         * @return a font index.
+         */
+        public @IntRange(from = 0) int getIndex() {
+            return mIndex;
+        }
+
+        /**
+         * Return a font variation settings.
+         *
+         * @return a font variation settings.
+         */
+        public @NonNull String getFontVariationSettings() {
+            return mFontVariationSettings;
+        }
+
+        /**
+         * Returns font family name that uses this font as a fallback.
+         *
+         * If this font is a fallback for the default font family, this is null.
+         *
+         * @return a font family name.
+         */
+        public @Nullable String getFallback() {
+            return mFallback;
         }
 
         /**
          * Returns the index to be used to access this font when accessing a TTC file.
+         * @deprecated Use getIndex instead.
+         * @hide
          */
+        @Deprecated
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
         public int getTtcIndex() {
-            return mTtcIndex;
+            return mIndex;
         }
 
         /**
          * Returns the list of axes associated to this font.
+         * @deprecated Use getFontVariationSettings
+         * @hide
          */
+        @Deprecated
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
         public @NonNull FontVariationAxis[] getAxes() {
-            return mAxes;
+            return FontVariationAxis.fromFontVariationSettings(mFontVariationSettings);
         }
 
         /**
          * Returns the weight value for this font.
+         * @deprecated Use getStyle instead.
+         * @hide
          */
+        @Deprecated
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
         public int getWeight() {
-            return mWeight;
+            return getStyle().getWeight();
         }
 
         /**
          * Returns whether this font is italic.
+         * @deprecated Use getStyle instead.
+         * @hide
          */
+        @Deprecated
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
         public boolean isItalic() {
-            return mIsItalic;
-        }
-
-        /**
-         * Returns the content uri associated to this font.
-         *
-         * You can reach to the font contents by calling {@link
-         * android.content.ContentResolver#openInputStream}.
-         */
-        public @Nullable Uri getUri() {
-            return mUri;
-        }
-
-        public void setUri(@NonNull Uri uri) {
-            mUri = uri;
-        }
-
-        public String getFallbackFor() {
-            return mFallbackFor;
+            return getStyle().getSlant() == FontStyle.FONT_SLANT_ITALIC;
         }
     }
 
     /**
-     * Class that holds information about a Font alias.
+     * A class represents alias between named font families.
+     *
+     * In the system font configuration, an font family can be an alias of another font family with
+     * different font weight. For example, "sans-serif-medium" can be a medium weight of
+     * sans-serif font family.
      */
     public static final class Alias {
-        private final @NonNull String mName;
-        private final @NonNull String mToName;
-        private final int mWeight;
+        private final @NonNull String mAliasName;
+        private final @NonNull String mReferName;
+        private final @IntRange(from = 0, to = 1000) int mWeight;
 
-        public Alias(@NonNull String name, @NonNull String toName, int weight) {
-            mName = name;
-            mToName = toName;
+        /**
+         * Construct an alias instance.
+         *
+         * @param aliasName an alias of the named font family.
+         * @param referName a referring font family name.
+         * @param weight a font weight of the referring font family.
+         * @hide Only system server can create this instance and passed via IPC.
+         */
+        public Alias(@NonNull String aliasName, @NonNull String referName,
+                @IntRange(from = 0, to = 1000) int weight) {
+            mAliasName = aliasName;
+            mReferName = referName;
             mWeight = weight;
         }
 
         /**
-         * Returns the new name for the alias.
+         * An alias of the named font family.
+         *
+         * @return an alias of the named font family.
          */
-        public @NonNull String getName() {
-            return mName;
+        public @NonNull String getAliasName() {
+            return mAliasName;
         }
 
         /**
-         * Returns the existing name to which this alias points to.
+         * A name of font family referring from {@link #getAliasName()}
+         *
+         * @return a referring font family name.
          */
-        public @NonNull String getToName() {
-            return mToName;
+        public @NonNull String getReferName() {
+            return mReferName;
         }
 
         /**
-         * Returns the weight associated with this alias.
+         * A font weight of the referring font family.
+         *
+         * @return a font weight of the referring font family.
          */
-        public int getWeight() {
+        public @IntRange(from = 0, to = 1000) int getWeight() {
             return mWeight;
         }
     }
 
     /**
-     * Class that holds information about a Font family.
+     * A class represents single font family entry in system font configuration.
+     *
+     * <p>
+     * A font family is a bundle of fonts for drawing text in various styles.
+     * For example, regular style font and bold style font can be bundled into a single font family,
+     * then system will select the correct style font from family for drawing.
      */
     public static final class Family {
-        private final @NonNull String mName;
-        private final @NonNull Font[] mFonts;
-        // Comma separated BCP47 complient locale strings
-        private final @NonNull String mLanguages;
+        private final @NonNull List<Font> mFonts;
+        private final @Nullable String mName;
+        private final @Nullable LocaleList mLocaleList;
+        private final @Variant int mVariant;
 
         /** @hide */
         @Retention(SOURCE)
@@ -212,26 +309,81 @@
         /**
          * Value for font variant.
          *
-         * Indiates the font is for elegant variant.
+         * Indicates the font is for elegant variant.
          * @see android.graphics.Paint#setElegantTextHeight
          */
         public static final int VARIANT_ELEGANT = 2;
 
-        // Must be same with Minikin's variant values.
-        // See frameworks/minikin/include/minikin/FontFamily.h
-        private final @Variant int mVariant;
-
-        public Family(@NonNull String name, @NonNull Font[] fonts, @NonNull String languages,
-                @Variant int variant) {
-            mName = name;
+        /**
+         * Construct a family instance.
+         *
+         * @hide Only system server can create this instance and passed via IPC.
+         */
+        public Family(@NonNull List<Font> fonts, @Nullable String name,
+                @Nullable LocaleList localeList, @Variant int variant) {
             mFonts = fonts;
-            mLanguages = languages;
+            mName = name;
+            mLocaleList = localeList;
             mVariant = variant;
         }
 
         /**
-         * Returns the name given by the system to this font family.
+         * Returns a list of font files in this family.
+         *
+         * @return a list of font files.
          */
+        public @NonNull List<Font> getFontList() {
+            return mFonts;
+        }
+
+        /**
+         * Returns a family name if this family defines a new fallback.
+         *
+         * @return non-null if a family name is associated. Otherwise null.
+         */
+        public @Nullable String getFallbackName() {
+            return mName;
+        }
+
+        /**
+         * Returns a locale list if associated.
+         *
+         * @return non-null if a locale list is associated. Otherwise null.
+         */
+        public @NonNull LocaleList getLocaleList() {
+            return mLocaleList;
+        }
+
+        /**
+         * Returns a text height variant.
+         *
+         * @return text height variant.
+         */
+        public @Variant int getTextHeightVariant() {
+            return mVariant;
+        }
+
+        /**
+         * Returns a family variant associated.
+         *
+         * @return a family variant.
+         * @deprecated Use getTextHeightVariant instead.
+         * @hide
+         */
+        @Deprecated
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+        public @Variant int getVariant() {
+            return mVariant;
+        }
+
+        /**
+         * Returns a family name if associated.
+         *
+         * @return non-null if a family name is associated. Otherwise null.
+         * @deprecated Use getFallbackName instead.
+         * @hide
+         */
+        @Deprecated
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
         public @Nullable String getName() {
             return mName;
@@ -239,25 +391,23 @@
 
         /**
          * Returns the list of fonts included in this family.
+         * @deprecated Use getFontFiles instead
+         * @hide
          */
+        @Deprecated
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
         public @Nullable Font[] getFonts() {
-            return mFonts;
+            return mFonts.toArray(new Font[0]);
         }
 
         /**
-         * Returns the comma separated BCP47 complient languages for this family. May be null.
+         * Returns the comma separated BCP47 compliant languages for this family. May be null.
+         * @deprecated Use getLocaleList instead
+         * @hide
          */
+        @Deprecated
         public @NonNull String getLanguages() {
-            return mLanguages;
-        }
-
-        /**
-         * Returns the font variant for this family, e.g. "elegant" or "compact". May be null.
-         */
-        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-        public @Variant int getVariant() {
-            return mVariant;
+            return mLocaleList.toLanguageTags();
         }
     }
 }
diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java
index 17d3ae4..471f2c2 100644
--- a/core/java/android/text/format/Formatter.java
+++ b/core/java/android/text/format/Formatter.java
@@ -24,11 +24,12 @@
 import android.icu.text.MeasureFormat;
 import android.icu.util.Measure;
 import android.icu.util.MeasureUnit;
-import android.net.NetworkUtils;
 import android.text.BidiFormatter;
 import android.text.TextUtils;
 import android.view.View;
 
+import com.android.net.module.util.Inet4AddressUtils;
+
 import java.util.Locale;
 
 /**
@@ -207,7 +208,7 @@
      */
     @Deprecated
     public static String formatIpAddress(int ipv4Address) {
-        return NetworkUtils.intToInetAddress(ipv4Address).getHostAddress();
+        return Inet4AddressUtils.intToInet4AddressHTL(ipv4Address).getHostAddress();
     }
 
     private static final int SECONDS_PER_MINUTE = 60;
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 2d26c64..b4e1172 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -642,7 +642,7 @@
         updateState(state);
         applyLocalVisibilityOverride();
 
-        if (!mState.equals(lastState, true /* excludingCaptionInsets */,
+        if (!mState.equals(lastState, false /* excludingCaptionInsets */,
                 true /* excludeInvisibleIme */)) {
             if (DEBUG) Log.d(TAG, "onStateChanged, notifyInsetsChanged");
             mHost.notifyInsetsChanged();
@@ -672,16 +672,14 @@
             getSourceConsumer(type).updateSource(source, animationType);
         }
         for (@InternalInsetsType int type = 0; type < InsetsState.SIZE; type++) {
+            // Only update the server side insets here.
+            if (type == ITYPE_CAPTION_BAR) continue;
             InsetsSource source = mState.peekSource(type);
             if (source == null) continue;
             if (newState.peekSource(type) == null) {
                 mState.removeSource(type);
             }
         }
-        if (mCaptionInsetsHeight != 0) {
-            mState.getSource(ITYPE_CAPTION_BAR).setFrame(new Rect(mFrame.left, mFrame.top,
-                    mFrame.right, mFrame.top + mCaptionInsetsHeight));
-        }
 
         updateDisabledUserAnimationTypes(disabledUserAnimationTypes);
 
@@ -1488,7 +1486,16 @@
 
     @Override
     public void setCaptionInsetsHeight(int height) {
-        mCaptionInsetsHeight = height;
+        if (mCaptionInsetsHeight != height) {
+            mCaptionInsetsHeight = height;
+            if (mCaptionInsetsHeight != 0) {
+                mState.getSource(ITYPE_CAPTION_BAR).setFrame(new Rect(mFrame.left, mFrame.top,
+                        mFrame.right, mFrame.top + mCaptionInsetsHeight));
+            } else {
+                mState.removeSource(ITYPE_CAPTION_BAR);
+            }
+            mHost.notifyInsetsChanged();
+        }
     }
 
     @Override
diff --git a/core/java/android/view/InsetsFlags.java b/core/java/android/view/InsetsFlags.java
index 5a64a5d..a334907 100644
--- a/core/java/android/view/InsetsFlags.java
+++ b/core/java/android/view/InsetsFlags.java
@@ -21,7 +21,7 @@
 import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
 import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS;
 import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS;
-import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE;
+import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT;
 import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
 
 import android.view.WindowInsetsController.Appearance;
@@ -60,13 +60,13 @@
 
     @ViewDebug.ExportedProperty(flagMapping = {
             @ViewDebug.FlagToString(
-                    mask = BEHAVIOR_SHOW_BARS_BY_SWIPE,
-                    equals = BEHAVIOR_SHOW_BARS_BY_SWIPE,
-                    name = "SHOW_BARS_BY_SWIPE"),
+                    mask = BEHAVIOR_DEFAULT,
+                    equals = BEHAVIOR_DEFAULT,
+                    name = "DEFAULT"),
             @ViewDebug.FlagToString(
                     mask = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE,
                     equals = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE,
                     name = "SHOW_TRANSIENT_BARS_BY_SWIPE")
     })
-    public @Behavior int behavior;
+    public @Behavior int behavior = BEHAVIOR_DEFAULT;
 }
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index bf377b0..d68e903 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -106,7 +106,9 @@
     public static final int ITYPE_NAVIGATION_BAR = 1;
     public static final int ITYPE_CAPTION_BAR = 2;
 
-    public static final int ITYPE_TOP_GESTURES = 3;
+    // The always visible types are visible to all windows regardless of the z-order.
+    public static final int FIRST_ALWAYS_VISIBLE_TYPE = 3;
+    public static final int ITYPE_TOP_GESTURES = FIRST_ALWAYS_VISIBLE_TYPE;
     public static final int ITYPE_BOTTOM_GESTURES = 4;
     public static final int ITYPE_LEFT_GESTURES = 5;
     public static final int ITYPE_RIGHT_GESTURES = 6;
@@ -117,15 +119,16 @@
     public static final int ITYPE_LEFT_MANDATORY_GESTURES = 9;
     public static final int ITYPE_RIGHT_MANDATORY_GESTURES = 10;
 
-    public static final int ITYPE_LEFT_TAPPABLE_ELEMENT = 11;
-    public static final int ITYPE_TOP_TAPPABLE_ELEMENT = 12;
-    public static final int ITYPE_RIGHT_TAPPABLE_ELEMENT = 13;
-    public static final int ITYPE_BOTTOM_TAPPABLE_ELEMENT = 14;
+    public static final int ITYPE_LEFT_DISPLAY_CUTOUT = 11;
+    public static final int ITYPE_TOP_DISPLAY_CUTOUT = 12;
+    public static final int ITYPE_RIGHT_DISPLAY_CUTOUT = 13;
+    public static final int ITYPE_BOTTOM_DISPLAY_CUTOUT = 14;
+    public static final int LAST_ALWAYS_VISIBLE_TYPE = ITYPE_BOTTOM_DISPLAY_CUTOUT;
 
-    public static final int ITYPE_LEFT_DISPLAY_CUTOUT = 15;
-    public static final int ITYPE_TOP_DISPLAY_CUTOUT = 16;
-    public static final int ITYPE_RIGHT_DISPLAY_CUTOUT = 17;
-    public static final int ITYPE_BOTTOM_DISPLAY_CUTOUT = 18;
+    public static final int ITYPE_LEFT_TAPPABLE_ELEMENT = 15;
+    public static final int ITYPE_TOP_TAPPABLE_ELEMENT = 16;
+    public static final int ITYPE_RIGHT_TAPPABLE_ELEMENT = 17;
+    public static final int ITYPE_BOTTOM_TAPPABLE_ELEMENT = 18;
 
     /** Input method window. */
     public static final int ITYPE_IME = 19;
@@ -182,6 +185,18 @@
     }
 
     /**
+     * Mirror the always visible sources from the other state. They will share the same object for
+     * the always visible types.
+     *
+     * @param other the state to mirror the mirrored sources from.
+     */
+    public void mirrorAlwaysVisibleInsetsSources(InsetsState other) {
+        for (int type = FIRST_ALWAYS_VISIBLE_TYPE; type <= LAST_ALWAYS_VISIBLE_TYPE; type++) {
+            mSources[type] = other.mSources[type];
+        }
+    }
+
+    /**
      * Calculates {@link WindowInsets} based on the current source configuration.
      *
      * @param frame The frame to calculate the insets relative to.
diff --git a/core/java/android/view/PendingInsetsController.java b/core/java/android/view/PendingInsetsController.java
index c018d1c..c61baf6 100644
--- a/core/java/android/view/PendingInsetsController.java
+++ b/core/java/android/view/PendingInsetsController.java
@@ -100,6 +100,9 @@
         if (mReplayedInsetsController != null) {
             return mReplayedInsetsController.getSystemBarsBehavior();
         }
+        if (mBehavior == KEEP_BEHAVIOR) {
+            return BEHAVIOR_DEFAULT;
+        }
         return mBehavior;
     }
 
diff --git a/core/java/android/view/RemoteAnimationTarget.java b/core/java/android/view/RemoteAnimationTarget.java
index ac5d14e..258a72c 100644
--- a/core/java/android/view/RemoteAnimationTarget.java
+++ b/core/java/android/view/RemoteAnimationTarget.java
@@ -270,7 +270,7 @@
         pw.print(" clipRect="); clipRect.printShortString(pw);
         pw.print(" contentInsets="); contentInsets.printShortString(pw);
         pw.print(" prefixOrderIndex="); pw.print(prefixOrderIndex);
-        pw.print(" position="); position.dump(pw);
+        pw.print(" position="); printPoint(position, pw);
         pw.print(" sourceContainerBounds="); sourceContainerBounds.printShortString(pw);
         pw.print(" screenSpaceBounds="); screenSpaceBounds.printShortString(pw);
         pw.print(" localBounds="); localBounds.printShortString(pw);
@@ -303,6 +303,10 @@
         proto.end(token);
     }
 
+    private static void printPoint(Point p, PrintWriter pw) {
+        pw.print("["); pw.print(p.x); pw.print(","); pw.print(p.y); pw.print("]");
+    }
+
     public static final @android.annotation.NonNull Creator<RemoteAnimationTarget> CREATOR
             = new Creator<RemoteAnimationTarget>() {
         public RemoteAnimationTarget createFromParcel(Parcel in) {
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 26e3bb2..7ac57b5 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -232,7 +232,7 @@
     private final Matrix mTmpMatrix = new Matrix();
 
     SurfaceControlViewHost.SurfacePackage mSurfacePackage;
-    private final boolean mUseBlastSync = false;
+    private final boolean mUseBlastSync = true;
 
     /**
      * Returns {@code true} if buffers should be submitted via blast
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 25967b3..b8840ba 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3790,7 +3790,7 @@
      * <p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only
      * has an effect when used in combination with that flag.</p>
      *
-     * @deprecated Use {@link WindowInsetsController#BEHAVIOR_SHOW_BARS_BY_SWIPE} instead.
+     * @deprecated Use {@link WindowInsetsController#BEHAVIOR_DEFAULT} instead.
      */
     @Deprecated
     public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 7e0ebbc..426edbc 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -26,7 +26,6 @@
 import static android.view.View.PFLAG_DRAW_ANIMATION;
 import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
 import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
-import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE;
 import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
@@ -55,8 +54,7 @@
 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
 import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
-import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE;
-import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_TOUCH;
+import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT;
 import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
@@ -2167,10 +2165,8 @@
             if ((sysUiVis & SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0
                     || (flags & FLAG_FULLSCREEN) != 0) {
                 inOutParams.insetsFlags.behavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
-            } else if ((sysUiVis & SYSTEM_UI_FLAG_IMMERSIVE) != 0) {
-                inOutParams.insetsFlags.behavior = BEHAVIOR_SHOW_BARS_BY_SWIPE;
             } else {
-                inOutParams.insetsFlags.behavior = BEHAVIOR_SHOW_BARS_BY_TOUCH;
+                inOutParams.insetsFlags.behavior = BEHAVIOR_DEFAULT;
             }
         }
 
@@ -9154,14 +9150,14 @@
      * Handles an inbound request for scroll capture from the system. If a client is not already
      * active, a search will be dispatched through the view tree to locate scrolling content.
      * <p>
-     * Either {@link IScrollCaptureCallbacks#onClientConnected(IScrollCaptureConnection, Rect,
+     * Either {@link IScrollCaptureCallbacks#onConnected(IScrollCaptureConnection, Rect,
      * Point)} or {@link IScrollCaptureCallbacks#onUnavailable()} will be returned
      * depending on the results of the search.
      *
      * @param callbacks to receive responses
      * @see ScrollCaptureTargetResolver
      */
-    private void handleScrollCaptureRequest(@NonNull IScrollCaptureCallbacks callbacks) {
+    public void handleScrollCaptureRequest(@NonNull IScrollCaptureCallbacks callbacks) {
         LinkedList<ScrollCaptureTarget> targetList = new LinkedList<>();
 
         // Window (root) level callbacks
@@ -9169,10 +9165,12 @@
 
         // Search through View-tree
         View rootView = getView();
-        Point point = new Point();
-        Rect rect = new Rect(0, 0, rootView.getWidth(), rootView.getHeight());
-        getChildVisibleRect(rootView, rect, point);
-        rootView.dispatchScrollCaptureSearch(rect, point, targetList);
+        if (rootView != null) {
+            Point point = new Point();
+            Rect rect = new Rect(0, 0, rootView.getWidth(), rootView.getHeight());
+            getChildVisibleRect(rootView, rect, point);
+            rootView.dispatchScrollCaptureSearch(rect, point, targetList);
+        }
 
         // No-op path. Scroll capture not offered for this window.
         if (targetList.isEmpty()) {
diff --git a/core/java/android/view/WindowInsetsController.java b/core/java/android/view/WindowInsetsController.java
index e879bb4..fb9bcbd 100644
--- a/core/java/android/view/WindowInsetsController.java
+++ b/core/java/android/view/WindowInsetsController.java
@@ -21,6 +21,7 @@
 import android.annotation.Nullable;
 import android.graphics.Insets;
 import android.inputmethodservice.InputMethodService;
+import android.os.Build;
 import android.os.CancellationSignal;
 import android.view.InsetsState.InternalInsetsType;
 import android.view.WindowInsets.Type;
@@ -77,22 +78,41 @@
     }
 
     /**
-     * The default option for {@link #setSystemBarsBehavior(int)}. System bars will be forcibly
-     * shown on any user interaction on the corresponding display if navigation bars are hidden by
+     * Option for {@link #setSystemBarsBehavior(int)}. System bars will be forcibly shown on any
+     * user interaction on the corresponding display if navigation bars are hidden by
      * {@link #hide(int)} or
      * {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)}.
+     * @deprecated This is not supported on Android {@link Build.VERSION_CODES#S} and later. Use
+     *             {@link #BEHAVIOR_DEFAULT} or {@link #BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE}
+     *             instead.
      */
+    @Deprecated
     int BEHAVIOR_SHOW_BARS_BY_TOUCH = 0;
 
     /**
+     * The default option for {@link #setSystemBarsBehavior(int)}: Window would like to remain
+     * interactive when hiding navigation bars by calling {@link #hide(int)} or
+     * {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)}.
+     *
+     * <p>When system bars are hidden in this mode, they can be revealed with system gestures, such
+     * as swiping from the edge of the screen where the bar is hidden from.</p>
+     *
+     * <p>When the gesture navigation is enabled, the system gestures can be triggered regardless
+     * the visibility of system bars.</p>
+     */
+    int BEHAVIOR_DEFAULT = 1;
+
+    /**
      * Option for {@link #setSystemBarsBehavior(int)}: Window would like to remain interactive when
      * hiding navigation bars by calling {@link #hide(int)} or
      * {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)}.
      *
      * <p>When system bars are hidden in this mode, they can be revealed with system gestures, such
      * as swiping from the edge of the screen where the bar is hidden from.</p>
+     * @deprecated Use {@link #BEHAVIOR_DEFAULT} instead.
      */
-    int BEHAVIOR_SHOW_BARS_BY_SWIPE = 1;
+    @Deprecated
+    int BEHAVIOR_SHOW_BARS_BY_SWIPE = BEHAVIOR_DEFAULT;
 
     /**
      * Option for {@link #setSystemBarsBehavior(int)}: Window would like to remain interactive when
@@ -111,8 +131,7 @@
      * @hide
      */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(value = {BEHAVIOR_SHOW_BARS_BY_TOUCH, BEHAVIOR_SHOW_BARS_BY_SWIPE,
-            BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE})
+    @IntDef(value = {BEHAVIOR_DEFAULT, BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE})
     @interface Behavior {
     }
 
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 4f7e841..45fa41b 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -663,24 +663,34 @@
     }
 
     /**
-     * Message for taking fullscreen screenshot
+     * Invoke screenshot flow to capture a full-screen image.
      * @hide
      */
     int TAKE_SCREENSHOT_FULLSCREEN = 1;
 
     /**
-     * Message for taking screenshot of selected region.
+     * Invoke screenshot flow allowing the user to select a region.
      * @hide
      */
     int TAKE_SCREENSHOT_SELECTED_REGION = 2;
 
     /**
-     * Message for handling a screenshot flow with an image provided by the caller.
+     * Invoke screenshot flow with an image provided by the caller.
      * @hide
      */
     int TAKE_SCREENSHOT_PROVIDED_IMAGE = 3;
 
     /**
+     * Enum listing the types of screenshot requests available.
+     *
+     * @hide
+     */
+    @IntDef({TAKE_SCREENSHOT_FULLSCREEN,
+            TAKE_SCREENSHOT_SELECTED_REGION,
+            TAKE_SCREENSHOT_PROVIDED_IMAGE})
+    @interface ScreenshotType {}
+
+    /**
      * Enum listing the possible sources from which a screenshot was originated. Used for logging.
      *
      * @hide
diff --git a/core/java/android/view/WindowManagerPolicyConstants.java b/core/java/android/view/WindowManagerPolicyConstants.java
index 8c35520..dd55f04 100644
--- a/core/java/android/view/WindowManagerPolicyConstants.java
+++ b/core/java/android/view/WindowManagerPolicyConstants.java
@@ -89,6 +89,15 @@
      */
     String EXTRA_FROM_HOME_KEY = "android.intent.extra.FROM_HOME_KEY";
 
+    /**
+     * Extra for the start reason of the HOME intent.
+     * Will be {@link PowerManager#WAKE_REASON_WAKE_KEY} or
+     * {@link PowerManager#WAKE_REASON_POWER_BUTTON} when intent was sent through
+     * {@link PhoneWindowManager#shouldWakeUpWithHomeIntent}.
+     * @hide
+     */
+    String EXTRA_START_REASON = "android.intent.extra.EXTRA_START_REASON";
+
     // TODO: move this to a more appropriate place.
     interface PointerEventListener {
         /**
diff --git a/core/java/android/view/accessibility/OWNERS b/core/java/android/view/accessibility/OWNERS
index 93b5a2e..b1d3967 100644
--- a/core/java/android/view/accessibility/OWNERS
+++ b/core/java/android/view/accessibility/OWNERS
@@ -9,3 +9,4 @@
 ogunwale@google.com
 jjaggi@google.com
 pweaver@google.com
+ryanlwlin@google.com
diff --git a/core/java/android/view/textclassifier/TextSelection.java b/core/java/android/view/textclassifier/TextSelection.java
index 5b32649..c1913f6 100644
--- a/core/java/android/view/textclassifier/TextSelection.java
+++ b/core/java/android/view/textclassifier/TextSelection.java
@@ -137,6 +137,15 @@
         return mExtras;
     }
 
+    /** @hide */
+    public TextSelection.Builder toBuilder() {
+        return new TextSelection.Builder(mStartIndex, mEndIndex)
+                .setId(mId)
+                .setEntityConfidence(mEntityConfidence)
+                .setTextClassification(mTextClassification)
+                .setExtras(mExtras);
+    }
+
     @Override
     public String toString() {
         return String.format(
@@ -188,6 +197,12 @@
             return this;
         }
 
+        Builder setEntityConfidence(EntityConfidence scores) {
+            mEntityConfidence.clear();
+            mEntityConfidence.putAll(scores.toMap());
+            return this;
+        }
+
         /**
          * Sets an id for the TextSelection object.
          */
diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java
index d34c8d5..578ed8c 100644
--- a/core/java/android/view/textservice/TextServicesManager.java
+++ b/core/java/android/view/textservice/TextServicesManager.java
@@ -17,8 +17,8 @@
 package android.view.textservice;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemService;
-import android.annotation.TestApi;
 import android.annotation.UserIdInt;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
@@ -34,6 +34,8 @@
 import com.android.internal.textservice.ISpellCheckerSessionListener;
 import com.android.internal.textservice.ITextServicesManager;
 
+import java.util.Arrays;
+import java.util.List;
 import java.util.Locale;
 
 /**
@@ -232,9 +234,22 @@
     }
 
     /**
-     * @hide
+     * Retrieve the list of currently enabled spell checkers, or null if there is none.
+     *
+     * @return The list of currently enabled spell checkers.
      */
-    @UnsupportedAppUsage
+    @Nullable
+    public List<SpellCheckerInfo> getEnabledSpellCheckersList() {
+        final SpellCheckerInfo[] enabledSpellCheckers = getEnabledSpellCheckers();
+        return enabledSpellCheckers != null ? Arrays.asList(enabledSpellCheckers) : null;
+    }
+
+    /**
+     * Retrieve the currently active spell checker, or null if there is none.
+     *
+     * @return The current active spell checker info.
+     */
+    @Nullable
     public SpellCheckerInfo getCurrentSpellChecker() {
         try {
             // Passing null as a locale for ICS
@@ -245,9 +260,13 @@
     }
 
     /**
-     * @hide
+     * Retrieve the selected subtype of the selected spell checker, or null if there is none.
+     *
+     * @param allowImplicitlySelectedSubtype {@code true} to return the default language matching
+     * system locale if there's no subtype selected explicitly, otherwise, returns null.
+     * @return The meta information of the selected subtype of the selected spell checker.
      */
-    @UnsupportedAppUsage
+    @Nullable
     public SpellCheckerSubtype getCurrentSpellCheckerSubtype(
             boolean allowImplicitlySelectedSubtype) {
         try {
@@ -258,10 +277,10 @@
     }
 
     /**
-     * @hide
+     * Return whether the spell checker is enabled or not.
+     *
+     * @return {@code true} if spell checker is enabled, {@code false} otherwise.
      */
-    @UnsupportedAppUsage
-    @TestApi
     public boolean isSpellCheckerEnabled() {
         try {
             return mService.isSpellCheckerEnabled(mUserId);
diff --git a/core/java/android/view/translation/ITranslationManager.aidl b/core/java/android/view/translation/ITranslationManager.aidl
index 73addf4..e175453 100644
--- a/core/java/android/view/translation/ITranslationManager.aidl
+++ b/core/java/android/view/translation/ITranslationManager.aidl
@@ -16,10 +16,15 @@
 
 package android.view.translation;
 
+import android.content.ComponentName;
+import android.os.IBinder;
 import android.service.translation.TranslationRequest;
+import android.view.autofill.AutofillId;
 import android.view.translation.TranslationSpec;
 import com.android.internal.os.IResultReceiver;
 
+import java.util.List;
+
 /**
  * Mediator between apps being translated and translation service implementation.
  *
@@ -29,4 +34,8 @@
     void getSupportedLocales(in IResultReceiver receiver, int userId);
     void onSessionCreated(in TranslationSpec sourceSpec, in TranslationSpec destSpec,
          int sessionId, in IResultReceiver receiver, int userId);
+
+    void updateUiTranslationState(int state, in TranslationSpec sourceSpec,
+         in TranslationSpec destSpec, in List<AutofillId> viewIds, in int taskId,
+         int userId);
 }
diff --git a/core/java/android/view/translation/UiTranslationManager.java b/core/java/android/view/translation/UiTranslationManager.java
new file mode 100644
index 0000000..eeb463a
--- /dev/null
+++ b/core/java/android/view/translation/UiTranslationManager.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.translation;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.os.RemoteException;
+import android.view.View;
+import android.view.autofill.AutofillId;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * The {@link UiTranslationManager} class provides ways for apps to use the ui translation
+ * function in framework.
+ *
+ * @hide
+ */
+@SystemApi
+public final class UiTranslationManager {
+
+    private static final String TAG = "UiTranslationManager";
+
+    /**
+     * The state caller request to disable utranslation,, it is no longer need to ui translation.
+     *
+     * @hide
+     */
+    public static final int STATE_UI_TRANSLATION_STARTED = 0;
+    /**
+     * The state caller request to pause ui translation, it will switch back to the original text.
+     *
+     * @hide
+     */
+    public static final int STATE_UI_TRANSLATION_PAUSED = 1;
+    /**
+     * The state caller request to resume the paused ui translation, it will show the translated
+     * text again if the text had been translated.
+     *
+     * @hide
+     */
+    public static final int STATE_UI_TRANSLATION_RESUMED = 2;
+    /**
+     * The state the caller request to enable ui translation.
+     *
+     * @hide
+     */
+    public static final int STATE_UI_TRANSLATION_FINISHED = 3;
+    /**
+     * @hide
+     */
+    @IntDef(prefix = {"STATE__TRANSLATION"}, value = {
+            STATE_UI_TRANSLATION_STARTED,
+            STATE_UI_TRANSLATION_PAUSED,
+            STATE_UI_TRANSLATION_RESUMED,
+            STATE_UI_TRANSLATION_FINISHED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface UiTranslationState {
+    }
+
+    @NonNull
+    private final Context mContext;
+
+    private final ITranslationManager mService;
+
+    /**
+     * @hide
+     */
+    public UiTranslationManager(@NonNull Context context, ITranslationManager service) {
+        mContext = Objects.requireNonNull(context);
+        mService = service;
+    }
+
+    /**
+     * Request ui translation for a given Views.
+     *
+     * @param sourceSpec {@link TranslationSpec} for the data to be translated.
+     * @param destSpec {@link TranslationSpec} for the translated data.
+     * @param viewIds A list of the {@link View}'s {@link AutofillId} which needs to be translated
+     * @param taskId the Activity Task id which needs ui translation
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
+    public void startTranslation(@NonNull TranslationSpec sourceSpec,
+            @NonNull TranslationSpec destSpec, @NonNull List<AutofillId> viewIds,
+            int taskId) {
+        // TODO(b/177789967): Return result code or find a way to notify the status.
+        // TODO(b/177394471): The is a temparary API, the expected is requestUiTranslation(
+        //  TranslationSpec, TranslationSpec,List<AutofillId>, Binder). We may need more time to
+        //  implement it, use task id as initial version for demo.
+        Objects.requireNonNull(sourceSpec);
+        Objects.requireNonNull(destSpec);
+        Objects.requireNonNull(viewIds);
+
+        try {
+            mService.updateUiTranslationState(STATE_UI_TRANSLATION_STARTED, sourceSpec,
+                    destSpec, viewIds, taskId, mContext.getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Request to disable the ui translation. It will destroy all the {@link Translator}s and no
+     * longer to show to show the translated text.
+     *
+     * @param taskId the Activity Task id which needs ui translation
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
+    public void finishTranslation(int taskId) {
+        try {
+            // TODO(b/177394471): The is a temparary API, the expected is finishUiTranslation(
+            //  Binder). We may need more time to implement it, use task id as initial version.
+            mService.updateUiTranslationState(STATE_UI_TRANSLATION_FINISHED,
+                    null /* sourceSpec */, null /* destSpec*/, null /* viewIds */, taskId,
+                    mContext.getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Request to pause the current ui translation's {@link Translator} which will switch back to
+     * the original language.
+     *
+     * @param taskId the Activity Task id which needs ui translation
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
+    public void pauseTranslation(int taskId) {
+        try {
+            // TODO(b/177394471): The is a temparary API, the expected is pauseUiTranslation(Binder)
+            // We may need more time to implement it, use task id as initial version for demo
+            mService.updateUiTranslationState(STATE_UI_TRANSLATION_PAUSED,
+                    null /* sourceSpec */, null /* destSpec*/, null /* viewIds */, taskId,
+                    mContext.getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Request to resume the paused ui translation's {@link Translator} which will switch to the
+     * translated language if the text had been translated.
+     *
+     * @param taskId the Activity Task id which needs ui translation
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
+    public void resumeTranslation(int taskId) {
+        try {
+            // TODO(b/177394471): The is a temparary API, the expected is resumeUiTranslation(
+            //  Binder). We may need more time to implement it, use task id as initial version.
+            mService.updateUiTranslationState(STATE_UI_TRANSLATION_RESUMED,
+                    null /* sourceSpec */, null /* destSpec*/, null /* viewIds */,
+                    taskId, mContext.getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+}
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index b9ff26b..6281ee9 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -39,6 +39,7 @@
 import android.view.inspector.InspectableProperty;
 
 import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 
 import java.util.ArrayList;
@@ -776,17 +777,23 @@
 
     /**
      * Grows {@code r} from its center such that each dimension is at least {@code minimumSize}.
+     *
+     * The result will still have the same {@link Rect#centerX()} and {@link Rect#centerY()} as the
+     * input.
+     *
+     * @hide
      */
-    private void growRectTo(Rect r, int minimumSize) {
-        int dy = (minimumSize - r.height()) / 2;
+    @VisibleForTesting
+    public void growRectTo(Rect r, int minimumSize) {
+        int dy = minimumSize - r.height();
         if (dy > 0) {
-            r.top -= dy;
-            r.bottom += dy;
+            r.top -= (dy + 1) / 2;
+            r.bottom += dy / 2;
         }
-        int dx = (minimumSize - r.width()) / 2;
+        int dx = minimumSize - r.width();
         if (dx > 0) {
-            r.left -= dx;
-            r.right += dx;
+            r.left -= (dx + 1) / 2;
+            r.right += dx / 2;
         }
     }
 
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index e4de400..ed20d26 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -196,11 +196,6 @@
 
         initImageView();
 
-        // ImageView is not important by default, unless app developer overrode attribute.
-        if (getImportantForAutofill() == IMPORTANT_FOR_AUTOFILL_AUTO) {
-            setImportantForAutofill(IMPORTANT_FOR_AUTOFILL_NO);
-        }
-
         final TypedArray a = context.obtainStyledAttributes(
                 attrs, R.styleable.ImageView, defStyleAttr, defStyleRes);
         saveAttributeDataForStyleable(context, R.styleable.ImageView,
@@ -265,6 +260,15 @@
             sCompatDrawableVisibilityDispatch = targetSdkVersion < Build.VERSION_CODES.N;
             sCompatDone = true;
         }
+
+        // By default, ImageView is not important for autofill but important for content capture.
+        // Developers can override these defaults via the corresponding attributes.
+        if (getImportantForAutofill() == IMPORTANT_FOR_AUTOFILL_AUTO) {
+            setImportantForAutofill(IMPORTANT_FOR_AUTOFILL_NO);
+        }
+        if (getImportantForContentCapture() == IMPORTANT_FOR_CONTENT_CAPTURE_AUTO) {
+            setImportantForContentCapture(IMPORTANT_FOR_CONTENT_CAPTURE_YES);
+        }
     }
 
     @Override
diff --git a/core/java/android/window/IRemoteTransition.aidl b/core/java/android/window/IRemoteTransition.aidl
new file mode 100644
index 0000000..e0ddf05
--- /dev/null
+++ b/core/java/android/window/IRemoteTransition.aidl
@@ -0,0 +1,46 @@
+/*
+ * 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.window;
+
+import android.view.IRemoteAnimationFinishedCallback;
+import android.view.SurfaceControl;
+import android.window.TransitionInfo;
+
+/**
+ * Interface allowing remote processes to play transition animations.
+ * The usage flow is as follows:
+ * <p><ol>
+ *  <li>The remote tags a lifecycle event with an IRemoteTransition (via a parameter in
+ *      ActivityOptions#makeRemoteAnimation) or a transition matches a filter registered via
+ *      Transitions#registerRemote.
+ *  <li>Shell then associates the transition for the event with the IRemoteTransition
+ *  <li>Shell receives onTransitionReady and delegates the animation to the IRemoteTransition
+ *      via {@link #startAnimation}.
+ *  <li>Once the IRemoteTransition is done animating, it will call the finishCallback.
+ *  <li>Shell/Core finish-up the transition.
+ * </ul>
+ *
+ * {@hide}
+ */
+oneway interface IRemoteTransition {
+    /**
+     * Starts a transition animation. Once complete, the implementation should call
+     * `finishCallback`.
+     */
+    void startAnimation(in TransitionInfo info, in SurfaceControl.Transaction t,
+            in IRemoteAnimationFinishedCallback finishCallback);
+}
diff --git a/core/java/android/window/ITransitionPlayer.aidl b/core/java/android/window/ITransitionPlayer.aidl
index 55d47cb..af37fbc 100644
--- a/core/java/android/window/ITransitionPlayer.aidl
+++ b/core/java/android/window/ITransitionPlayer.aidl
@@ -16,10 +16,9 @@
 
 package android.window;
 
-import android.app.ActivityManager;
 import android.view.SurfaceControl;
 import android.window.TransitionInfo;
-import android.window.WindowContainerTransaction;
+import android.window.TransitionRequestInfo;
 
 /**
  * Implemented by WMShell to initiate and play transition animations.
@@ -56,12 +55,9 @@
      * Called when something in WMCore requires a transition to play -- for example when an Activity
      * is started in a new Task.
      *
-     * @param type The {@link WindowManager#TransitionType} of the transition to start.
      * @param transitionToken An identifying token for the transition that needs to be started.
      *                        Pass this to {@link IWindowOrganizerController#startTransition}.
-     * @param triggerTask If non-null, the task containing the activity whose lifecycle change
-     *                    (start or finish) has caused this transition to occur.
+     * @param request Information about this particular request.
      */
-    void requestStartTransition(int type, in IBinder transitionToken,
-            in ActivityManager.RunningTaskInfo triggerTask);
+    void requestStartTransition(in IBinder transitionToken, in TransitionRequestInfo request);
 }
diff --git a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl b/core/java/android/window/TransitionFilter.aidl
similarity index 64%
copy from media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl
copy to core/java/android/window/TransitionFilter.aidl
index edf96dd..19c76d1 100644
--- a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl
+++ b/core/java/android/window/TransitionFilter.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.
@@ -14,17 +14,6 @@
  * limitations under the License.
  */
 
-package android.media.tv.tunerresourcemanager;
+package android.window;
 
-/**
- * Simple container of the FrontendInfo struct defined in the TunerHAL 1.0 interface.
- *
- * @hide
- */
-parcelable TunerFrontendInfo {
-    int handle;
-
-    int frontendType;
-
-    int exclusiveGroupId;
-}
+parcelable TransitionFilter;
diff --git a/core/java/android/window/TransitionFilter.java b/core/java/android/window/TransitionFilter.java
new file mode 100644
index 0000000..4421f06
--- /dev/null
+++ b/core/java/android/window/TransitionFilter.java
@@ -0,0 +1,215 @@
+/*
+ * 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.window;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.WindowConfiguration;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A parcelable filter that can be used for rerouting transitions to a remote. This is a local
+ * representation so that the transition system doesn't need to make blocking queries over
+ * binder.
+ *
+ * @hide
+ */
+public final class TransitionFilter implements Parcelable {
+
+    /**
+     * When non-null: this is a list of transition types that this filter applies to. This filter
+     * will fail for transitions that aren't one of these types.
+     */
+    @Nullable public int[] mTypeSet = null;
+
+    /**
+     * A list of required changes. To pass, a transition must meet all requirements.
+     */
+    @Nullable public Requirement[] mRequirements = null;
+
+    public TransitionFilter() {
+    }
+
+    private TransitionFilter(Parcel in) {
+        mTypeSet = in.createIntArray();
+        mRequirements = in.createTypedArray(Requirement.CREATOR);
+    }
+
+    /** @return true if `info` meets all the requirements to pass this filter. */
+    public boolean matches(@NonNull TransitionInfo info) {
+        if (mTypeSet != null) {
+            // non-null typeset, so make sure info is one of the types.
+            boolean typePass = false;
+            for (int i = 0; i < mTypeSet.length; ++i) {
+                if (info.getType() == mTypeSet[i]) {
+                    typePass = true;
+                    break;
+                }
+            }
+            if (!typePass) return false;
+        }
+        // Make sure info meets all of the requirements.
+        if (mRequirements != null) {
+            for (int i = 0; i < mRequirements.length; ++i) {
+                if (!mRequirements[i].matches(info)) return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    /** @hide */
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeIntArray(mTypeSet);
+        dest.writeTypedArray(mRequirements, flags);
+    }
+
+    @NonNull
+    public static final Creator<TransitionFilter> CREATOR =
+            new Creator<TransitionFilter>() {
+                @Override
+                public TransitionFilter createFromParcel(Parcel in) {
+                    return new TransitionFilter(in);
+                }
+
+                @Override
+                public TransitionFilter[] newArray(int size) {
+                    return new TransitionFilter[size];
+                }
+            };
+
+    @Override
+    /** @hide */
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("{types=[");
+        if (mTypeSet != null) {
+            for (int i = 0; i < mTypeSet.length; ++i) {
+                sb.append((i == 0 ? "" : ",") + mTypeSet[i]);
+            }
+        }
+        sb.append("] checks=[");
+        if (mRequirements != null) {
+            for (int i = 0; i < mRequirements.length; ++i) {
+                sb.append((i == 0 ? "" : ",") + mRequirements[i]);
+            }
+        }
+        return sb.append("]}").toString();
+    }
+
+    /**
+     * Matches a change that a transition must contain to pass this filter. All requirements in a
+     * filter must be met to pass the filter.
+     */
+    public static final class Requirement implements Parcelable {
+        public int mActivityType = ACTIVITY_TYPE_UNDEFINED;
+        public int[] mModes = null;
+
+        public Requirement() {
+        }
+
+        private Requirement(Parcel in) {
+            mActivityType = in.readInt();
+            mModes = in.createIntArray();
+        }
+
+        /** Go through changes and find if at-least one change matches this filter */
+        boolean matches(@NonNull TransitionInfo info) {
+            for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+                final TransitionInfo.Change change = info.getChanges().get(i);
+                if (change.getParent() != null) {
+                    // Only look at the top animating windows.
+                    continue;
+                }
+                if (mActivityType != ACTIVITY_TYPE_UNDEFINED) {
+                    if (change.getTaskInfo() == null
+                            || change.getTaskInfo().getActivityType() != mActivityType) {
+                        continue;
+                    }
+                }
+                if (mModes != null) {
+                    boolean pass = false;
+                    for (int m = 0; m < mModes.length; ++m) {
+                        if (mModes[m] == change.getMode()) {
+                            pass = true;
+                            break;
+                        }
+                    }
+                    if (!pass) continue;
+                }
+                return true;
+            }
+            return false;
+        }
+
+        /** Check if the request matches this filter. It may generate false positives */
+        boolean matches(@NonNull TransitionRequestInfo request) {
+            // Can't check modes since the transition hasn't been built at this point.
+            if (mActivityType == ACTIVITY_TYPE_UNDEFINED) return true;
+            return request.getTriggerTask() != null
+                    && request.getTriggerTask().getActivityType() == mActivityType;
+        }
+
+        @Override
+        /** @hide */
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
+            dest.writeInt(mActivityType);
+            dest.writeIntArray(mModes);
+        }
+
+        @NonNull
+        public static final Creator<Requirement> CREATOR =
+                new Creator<Requirement>() {
+                    @Override
+                    public Requirement createFromParcel(Parcel in) {
+                        return new Requirement(in);
+                    }
+
+                    @Override
+                    public Requirement[] newArray(int size) {
+                        return new Requirement[size];
+                    }
+                };
+
+        @Override
+        /** @hide */
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder out = new StringBuilder();
+            out.append("{atype=" + WindowConfiguration.activityTypeToString(mActivityType));
+            out.append(" modes=[");
+            if (mModes != null) {
+                for (int i = 0; i < mModes.length; ++i) {
+                    out.append((i == 0 ? "" : ",") + TransitionInfo.modeToString(mModes[i]));
+                }
+            }
+            return out.append("]}").toString();
+        }
+    }
+}
diff --git a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl b/core/java/android/window/TransitionRequestInfo.aidl
similarity index 64%
copy from media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl
copy to core/java/android/window/TransitionRequestInfo.aidl
index edf96dd..d2b9ccf 100644
--- a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl
+++ b/core/java/android/window/TransitionRequestInfo.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.
@@ -14,17 +14,6 @@
  * limitations under the License.
  */
 
-package android.media.tv.tunerresourcemanager;
+package android.window;
 
-/**
- * Simple container of the FrontendInfo struct defined in the TunerHAL 1.0 interface.
- *
- * @hide
- */
-parcelable TunerFrontendInfo {
-    int handle;
-
-    int frontendType;
-
-    int exclusiveGroupId;
-}
+parcelable TransitionRequestInfo;
diff --git a/core/java/android/window/TransitionRequestInfo.java b/core/java/android/window/TransitionRequestInfo.java
new file mode 100644
index 0000000..cc493ab
--- /dev/null
+++ b/core/java/android/window/TransitionRequestInfo.java
@@ -0,0 +1,208 @@
+/*
+ * 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.window;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.os.Parcelable;
+import android.view.WindowManager;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * Used to communicate information about what is changing during a transition to a TransitionPlayer.
+ * @hide
+ */
+@DataClass(genToString = true, genSetters = true, genAidl = true)
+public final class TransitionRequestInfo implements Parcelable {
+
+    /** The type of the transition being requested. */
+    private final @WindowManager.TransitionType int mType;
+
+    /**
+     * If non-null, If non-null, the task containing the activity whose lifecycle change (start or
+     * finish) has caused this transition to occur.
+     */
+    private @Nullable ActivityManager.RunningTaskInfo mTriggerTask;
+
+    /** If non-null, a remote-transition associated with the source of this transition. */
+    private @Nullable IRemoteTransition mRemoteTransition;
+
+
+
+    // 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/window/TransitionRequestInfo.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /**
+     * Creates a new TransitionRequestInfo.
+     *
+     * @param type
+     *   The type of the transition being requested.
+     * @param triggerTask
+     *   If non-null, If non-null, the task containing the activity whose lifecycle change (start or
+     *   finish) has caused this transition to occur.
+     * @param remoteTransition
+     *   If non-null, a remote-transition associated with the source of this transition.
+     */
+    @DataClass.Generated.Member
+    public TransitionRequestInfo(
+            @WindowManager.TransitionType int type,
+            @Nullable ActivityManager.RunningTaskInfo triggerTask,
+            @Nullable IRemoteTransition remoteTransition) {
+        this.mType = type;
+        com.android.internal.util.AnnotationValidations.validate(
+                WindowManager.TransitionType.class, null, mType);
+        this.mTriggerTask = triggerTask;
+        this.mRemoteTransition = remoteTransition;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    /**
+     * The type of the transition being requested.
+     */
+    @DataClass.Generated.Member
+    public @WindowManager.TransitionType int getType() {
+        return mType;
+    }
+
+    /**
+     * If non-null, If non-null, the task containing the activity whose lifecycle change (start or
+     * finish) has caused this transition to occur.
+     */
+    @DataClass.Generated.Member
+    public @Nullable ActivityManager.RunningTaskInfo getTriggerTask() {
+        return mTriggerTask;
+    }
+
+    /**
+     * If non-null, a remote-transition associated with the source of this transition.
+     */
+    @DataClass.Generated.Member
+    public @Nullable IRemoteTransition getRemoteTransition() {
+        return mRemoteTransition;
+    }
+
+    /**
+     * If non-null, If non-null, the task containing the activity whose lifecycle change (start or
+     * finish) has caused this transition to occur.
+     */
+    @DataClass.Generated.Member
+    public @android.annotation.NonNull TransitionRequestInfo setTriggerTask(@android.annotation.NonNull ActivityManager.RunningTaskInfo value) {
+        mTriggerTask = value;
+        return this;
+    }
+
+    /**
+     * If non-null, a remote-transition associated with the source of this transition.
+     */
+    @DataClass.Generated.Member
+    public @android.annotation.NonNull TransitionRequestInfo setRemoteTransition(@android.annotation.NonNull IRemoteTransition value) {
+        mRemoteTransition = value;
+        return this;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "TransitionRequestInfo { " +
+                "type = " + mType + ", " +
+                "triggerTask = " + mTriggerTask + ", " +
+                "remoteTransition = " + mRemoteTransition +
+        " }";
+    }
+
+    @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) { ... }
+
+        byte flg = 0;
+        if (mTriggerTask != null) flg |= 0x2;
+        if (mRemoteTransition != null) flg |= 0x4;
+        dest.writeByte(flg);
+        dest.writeInt(mType);
+        if (mTriggerTask != null) dest.writeTypedObject(mTriggerTask, flags);
+        if (mRemoteTransition != null) dest.writeStrongInterface(mRemoteTransition);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ TransitionRequestInfo(@android.annotation.NonNull android.os.Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        byte flg = in.readByte();
+        int type = in.readInt();
+        ActivityManager.RunningTaskInfo triggerTask = (flg & 0x2) == 0 ? null : (ActivityManager.RunningTaskInfo) in.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR);
+        IRemoteTransition remoteTransition = (flg & 0x4) == 0 ? null : IRemoteTransition.Stub.asInterface(in.readStrongBinder());
+
+        this.mType = type;
+        com.android.internal.util.AnnotationValidations.validate(
+                WindowManager.TransitionType.class, null, mType);
+        this.mTriggerTask = triggerTask;
+        this.mRemoteTransition = remoteTransition;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @android.annotation.NonNull Parcelable.Creator<TransitionRequestInfo> CREATOR
+            = new Parcelable.Creator<TransitionRequestInfo>() {
+        @Override
+        public TransitionRequestInfo[] newArray(int size) {
+            return new TransitionRequestInfo[size];
+        }
+
+        @Override
+        public TransitionRequestInfo createFromParcel(@android.annotation.NonNull android.os.Parcel in) {
+            return new TransitionRequestInfo(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1610060387917L,
+            codegenVersion = "1.0.22",
+            sourceFile = "frameworks/base/core/java/android/window/TransitionRequestInfo.java",
+            inputSignatures = "private final @android.view.WindowManager.TransitionType int mType\nprivate @android.annotation.Nullable android.app.ActivityManager.RunningTaskInfo mTriggerTask\nprivate @android.annotation.Nullable android.window.IRemoteTransition mRemoteTransition\nclass TransitionRequestInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genSetters=true, genAidl=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index c235c82..6cfd498 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -182,7 +182,7 @@
      * To be used for shared element transition into this activity.
      * @hide
      */
-    public static final String FIRST_IMAGE_PREVIEW_TRANSITION_NAME = "chooser_preview_image_1";
+    public static final String FIRST_IMAGE_PREVIEW_TRANSITION_NAME = "screenshot_preview_image";
 
     private static final String PREF_NUM_SHEET_EXPANSIONS = "pref_num_sheet_expansions";
 
diff --git a/core/java/com/android/internal/app/ChooserActivityLogger.java b/core/java/com/android/internal/app/ChooserActivityLogger.java
index c0cc483..47d8334 100644
--- a/core/java/com/android/internal/app/ChooserActivityLogger.java
+++ b/core/java/com/android/internal/app/ChooserActivityLogger.java
@@ -120,7 +120,7 @@
         @UiEvent(doc = "User selected the nearby target.")
         SHARESHEET_NEARBY_TARGET_SELECTED(626),
         @UiEvent(doc = "User selected the edit target.")
-        SHARESHEET_EDIT_TARGET_SELECTED(627);
+        SHARESHEET_EDIT_TARGET_SELECTED(669);
 
         private final int mId;
         SharesheetTargetSelectedEvent(int id) {
diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java
index c0648ab..2e7629a 100644
--- a/core/java/com/android/internal/net/VpnConfig.java
+++ b/core/java/com/android/internal/net/VpnConfig.java
@@ -129,7 +129,7 @@
         String[] routes = routesStr.trim().split(" ");
         for (String route : routes) {
             //each route is ip/prefix
-            RouteInfo info = new RouteInfo(new IpPrefix(route), null);
+            RouteInfo info = new RouteInfo(new IpPrefix(route), null, null, RouteInfo.RTN_UNICAST);
             this.routes.add(info);
             updateAllowedFamilies(info.getDestination().getAddress());
         }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 33aa190..f105320 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -19,6 +19,8 @@
 import static android.os.BatteryStatsManager.NUM_WIFI_STATES;
 import static android.os.BatteryStatsManager.NUM_WIFI_SUPPL_STATES;
 
+import static com.android.internal.power.MeasuredEnergyStats.NUMBER_ENERGY_BUCKETS;
+
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -103,7 +105,6 @@
 import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidClusterTimeReader;
 import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader;
 import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidUserSysTimeReader;
-import com.android.internal.power.MeasuredEnergyArray;
 import com.android.internal.power.MeasuredEnergyStats;
 import com.android.internal.power.MeasuredEnergyStats.EnergyBucket;
 import com.android.internal.util.ArrayUtils;
@@ -370,14 +371,6 @@
          * @param railStats
          */
         void fillRailDataStats(RailStats railStats);
-        /**
-         * Function to get energy consumption data
-         *
-         * @return an array of measured energy (in microjoules) since boot, will be null if
-         * measured energy data is unavailable
-         */
-        @Nullable
-        MeasuredEnergyArray getEnergyConsumptionData();
     }
 
     public static abstract class UserInfoProvider {
@@ -10704,15 +10697,13 @@
     }
 
     public BatteryStatsImpl(File systemDir, Handler handler, PlatformIdleStateCallback cb,
-            MeasuredEnergyRetriever energyStatsCb, boolean[] supportedEnergyBuckets,
-            UserInfoProvider userInfoProvider) {
-        this(new SystemClocks(), systemDir, handler, cb, energyStatsCb, supportedEnergyBuckets,
-                userInfoProvider);
+            MeasuredEnergyRetriever energyStatsCb, UserInfoProvider userInfoProvider) {
+        this(new SystemClocks(), systemDir, handler, cb, energyStatsCb, userInfoProvider);
     }
 
     private BatteryStatsImpl(Clocks clocks, File systemDir, Handler handler,
             PlatformIdleStateCallback cb, MeasuredEnergyRetriever energyStatsCb,
-            boolean[] supportedEnergyBuckets, UserInfoProvider userInfoProvider) {
+            UserInfoProvider userInfoProvider) {
         init(clocks);
 
         if (systemDir == null) {
@@ -10818,10 +10809,6 @@
         // Notify statsd that the system is initially not in doze.
         mDeviceIdleMode = DEVICE_IDLE_MODE_OFF;
         FrameworkStatsLog.write(FrameworkStatsLog.DEVICE_IDLE_MODE_STATE_CHANGED, mDeviceIdleMode);
-
-        mGlobalMeasuredEnergyStats = supportedEnergyBuckets == null ? null :
-                new MeasuredEnergyStats(supportedEnergyBuckets);
-        mScreenStateAtLastEnergyMeasurement = mScreenState;
     }
 
     @UnsupportedAppUsage
@@ -12503,21 +12490,6 @@
     }
 
     /**
-     * Get energy consumed (in microjoules) by a set of subsystems from the {@link
-     * MeasuredEnergyRetriever}, if available.
-     *
-     * @return a SparseLongArray that maps consumer id to energy consumed. Returns null if data is
-     * unavailable.
-     */
-    @Nullable
-    public MeasuredEnergyArray getEnergyConsumptionDataLocked() {
-        if (mMeasuredEnergyRetriever == null) {
-            return null;
-        }
-        return mMeasuredEnergyRetriever.getEnergyConsumptionData();
-    }
-
-    /**
      * Read and distribute kernel wake lock use across apps.
      */
     public void updateKernelWakelocksLocked() {
@@ -14240,6 +14212,40 @@
         mConstants.startObserving(context.getContentResolver());
         registerUsbStateReceiver(context);
     }
+    /**
+     * Initialize the measured energy stats data structures.
+     *
+     * @param supportedEnergyBuckets boolean array indicating which buckets are currently supported
+     */
+    @GuardedBy("this")
+    public void initMeasuredEnergyStatsLocked(boolean[] supportedEnergyBuckets) {
+        boolean supportedBucketMismatch = false;
+        mScreenStateAtLastEnergyMeasurement = mScreenState;
+
+        if (supportedEnergyBuckets == null) {
+            if (mGlobalMeasuredEnergyStats != null) {
+                // Measured energy buckets no longer supported, wipe out the existing data.
+                supportedBucketMismatch = true;
+            }
+        } else if (mGlobalMeasuredEnergyStats == null) {
+            mGlobalMeasuredEnergyStats = new MeasuredEnergyStats(supportedEnergyBuckets);
+            return;
+        } else {
+            for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
+                if (mGlobalMeasuredEnergyStats.isEnergyBucketSupported(i)
+                        != supportedEnergyBuckets[i]) {
+                    supportedBucketMismatch = true;
+                    break;
+                }
+            }
+        }
+
+        if (supportedBucketMismatch) {
+            // Supported energy buckets changed since last boot.
+            // Existing data is no longer reliable.
+            resetAllStatsLocked(SystemClock.uptimeMillis(), SystemClock.elapsedRealtime());
+        }
+    }
 
     @VisibleForTesting
     public final class Constants extends ContentObserver {
@@ -14919,7 +14925,11 @@
         mNextMaxDailyDeadlineMs = in.readLong();
         mBatteryTimeToFullSeconds = in.readLong();
 
-        MeasuredEnergyStats.readSummaryFromParcel(mGlobalMeasuredEnergyStats, in);
+        /**
+         * WARNING: Supported buckets may have changed across boots. Bucket mismatch is handled
+         *          later when {@link #initMeasuredEnergyStatsLocked} is called.
+         */
+        mGlobalMeasuredEnergyStats = MeasuredEnergyStats.createAndReadSummaryFromParcel(in);
 
         mStartCount++;
 
@@ -15417,7 +15427,7 @@
         out.writeLong(mNextMaxDailyDeadlineMs);
         out.writeLong(mBatteryTimeToFullSeconds);
 
-        MeasuredEnergyStats.writeSummaryToParcel(mGlobalMeasuredEnergyStats, out);
+        MeasuredEnergyStats.writeSummaryToParcel(mGlobalMeasuredEnergyStats, out, false);
 
         mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         mScreenDozeTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
@@ -15742,7 +15752,7 @@
                 out.writeInt(0);
             }
 
-            MeasuredEnergyStats.writeSummaryToParcel(u.mUidMeasuredEnergyStats, out);
+            MeasuredEnergyStats.writeSummaryToParcel(u.mUidMeasuredEnergyStats, out, true);
 
             final ArrayMap<String, Uid.Wakelock> wakeStats = u.mWakelockStats.getMap();
             int NW = wakeStats.size();
diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java
index 790d7f7..6860759e 100644
--- a/core/java/com/android/internal/os/WrapperInit.java
+++ b/core/java/com/android/internal/os/WrapperInit.java
@@ -69,15 +69,16 @@
         // Tell the Zygote what our actual PID is (since it only knows about the
         // wrapper that it directly forked).
         if (fdNum != 0) {
+            FileDescriptor fd = new FileDescriptor();
             try {
-                FileDescriptor fd = new FileDescriptor();
                 fd.setInt$(fdNum);
                 DataOutputStream os = new DataOutputStream(new FileOutputStream(fd));
                 os.writeInt(Process.myPid());
                 os.close();
-                IoUtils.closeQuietly(fd);
             } catch (IOException ex) {
                 Slog.d(TAG, "Could not write pid of wrapped process to Zygote pipe.", ex);
+            } finally {
+                IoUtils.closeQuietly(fd);
             }
         }
 
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 4512fba..adebde0 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -2019,6 +2019,7 @@
             if (getForeground() != null) {
                 drawableChanged();
             }
+            notifyCaptionHeightChanged();
         }
     }
 
diff --git a/core/java/com/android/internal/power/MeasuredEnergyStats.java b/core/java/com/android/internal/power/MeasuredEnergyStats.java
index b644df4..b744a5d 100644
--- a/core/java/com/android/internal/power/MeasuredEnergyStats.java
+++ b/core/java/com/android/internal/power/MeasuredEnergyStats.java
@@ -130,12 +130,16 @@
      * Note: {@link com.android.internal.os.BatteryStatsImpl#VERSION} must be updated if summary
      *       parceling changes.
      */
-    private void readSummaryFromParcel(Parcel in) {
+    private void readSummaryFromParcel(Parcel in, boolean overwriteAvailability) {
         final int size = in.readInt();
         for (int i = 0; i < size; i++) {
             final int bucket = in.readInt();
             final long energyUJ = in.readLong();
-            setValueIfSupported(bucket, energyUJ);
+            if (overwriteAvailability) {
+                mAccumulatedEnergiesMicroJoules[bucket] = energyUJ;
+            } else {
+                setValueIfSupported(bucket, energyUJ);
+            }
         }
     }
 
@@ -143,14 +147,15 @@
      * Write to summary parcel.
      * Note: Measured subsystem availability may be different when the summary parcel is read.
      */
-    private void writeSummaryToParcel(Parcel out) {
+    private void writeSummaryToParcel(Parcel out, boolean skipZero) {
         final int sizePos = out.dataPosition();
         out.writeInt(0);
         int size = 0;
         // Write only the supported buckets with non-zero energy.
         for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
             final long energy = mAccumulatedEnergiesMicroJoules[i];
-            if (energy <= 0) continue;
+            if (energy < 0) continue;
+            if (energy == 0 && skipZero) continue;
 
             out.writeInt(i);
             out.writeLong(mAccumulatedEnergiesMicroJoules[i]);
@@ -197,16 +202,19 @@
     }
 
     /**
-     * Populate a MeasuredEnergyStats from a parcel. If the stats is null, consume and
-     * ignore the parcelled data.
+     * Create a MeasuredEnergyStats object from a summary parcel.
+     *
+     * @return a new MeasuredEnergyStats object as described.
+     *         Returns null if the parcel indicates there is no data to populate.
      */
-    public static void readSummaryFromParcel(@Nullable MeasuredEnergyStats stats, Parcel in) {
+    public static @Nullable MeasuredEnergyStats createAndReadSummaryFromParcel(Parcel in) {
         // Check if any MeasuredEnergyStats exists on the parcel
-        if (in.readInt() == 0) return;
+        if (in.readInt() == 0) return null;
 
-        // If stats is null, create a placeholder MeasuredEnergyStats to consume the parcel data
-        final MeasuredEnergyStats mes = stats != null ? stats : new MeasuredEnergyStats();
-        mes.readSummaryFromParcel(in);
+        final MeasuredEnergyStats stats =
+                new MeasuredEnergyStats(new boolean[NUMBER_ENERGY_BUCKETS]);
+        stats.readSummaryFromParcel(in, true);
+        return stats;
     }
 
     /**
@@ -227,12 +235,12 @@
         if (template == null) {
             // Nothing supported now. Create placeholder object just to consume the parcel data.
             final MeasuredEnergyStats mes = new MeasuredEnergyStats();
-            mes.readSummaryFromParcel(in);
+            mes.readSummaryFromParcel(in, false);
             return null;
         }
 
         final MeasuredEnergyStats stats = createFromTemplate(template);
-        stats.readSummaryFromParcel(in);
+        stats.readSummaryFromParcel(in, false);
         if (stats.containsInterestingData()) {
             return stats;
         } else {
@@ -253,13 +261,13 @@
      * Write a MeasuredEnergyStats to a parcel. If the stats is null, just write a 0.
      */
     public static void writeSummaryToParcel(@Nullable MeasuredEnergyStats stats,
-            Parcel dest) {
+            Parcel dest, boolean skipZero) {
         if (stats == null) {
             dest.writeInt(0);
             return;
         }
         dest.writeInt(1);
-        stats.writeSummaryToParcel(dest);
+        stats.writeSummaryToParcel(dest, skipZero);
     }
 
     /** Reset accumulated energy. */
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index b9c2fd5..200e0dd 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -41,7 +41,6 @@
 
     void showWirelessChargingAnimation(int batteryLevel);
 
-    void topAppWindowChanged(int displayId, boolean isFullscreen, boolean isImmersive);
     void setImeWindowStatus(int displayId, in IBinder token, int vis, int backDisposition,
             boolean showImeSwitcher, boolean isMultiClientImeEnabled);
     void setWindowState(int display, int window, int state);
@@ -167,7 +166,7 @@
     void onRecentsAnimationStateChanged(boolean running);
 
     /**
-     * Notifies System UI side of system bar appearance change on the specified display.
+     * Notifies System UI side of system bar attribute change on the specified display.
      *
      * @param displayId the ID of the display to notify
      * @param appearance the appearance of the focused window. The light top bar appearance is not
@@ -177,9 +176,12 @@
      *                         bar, that the bar can have partial appearances in corresponding
      *                         stacks.
      * @param navbarColorManagedByIme {@code true} if navigation bar color is managed by IME.
+     * @param behavior the behavior of the focused window.
+     * @param isFullscreen whether any of status or navigation bar is requested invisible.
      */
-    void onSystemBarAppearanceChanged(int displayId, int appearance,
-            in AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme);
+    void onSystemBarAttributesChanged(int displayId, int appearance,
+            in AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
+            int behavior, boolean isFullscreen);
 
     /**
      * Notifies System UI to show transient bars. The transient bars are system bars, e.g., status
diff --git a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
index 9095f05..8fb2f9c 100644
--- a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
+++ b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
@@ -38,14 +38,14 @@
     public final int mDisabledFlags2;                   // switch[6]
     public final IBinder mImeToken;
     public final boolean mNavbarColorManagedByIme;
+    public final int mBehavior;
     public final boolean mAppFullscreen;
-    public final boolean mAppImmersive;
     public final int[] mTransientBarTypes;
 
     public RegisterStatusBarResult(ArrayMap<String, StatusBarIcon> icons, int disabledFlags1,
             int appearance, AppearanceRegion[] appearanceRegions, int imeWindowVis,
             int imeBackDisposition, boolean showImeSwitcher, int disabledFlags2, IBinder imeToken,
-            boolean navbarColorManagedByIme, boolean appFullscreen, boolean appImmersive,
+            boolean navbarColorManagedByIme, int behavior, boolean appFullscreen,
             @NonNull int[] transientBarTypes) {
         mIcons = new ArrayMap<>(icons);
         mDisabledFlags1 = disabledFlags1;
@@ -57,8 +57,8 @@
         mDisabledFlags2 = disabledFlags2;
         mImeToken = imeToken;
         mNavbarColorManagedByIme = navbarColorManagedByIme;
+        mBehavior = behavior;
         mAppFullscreen = appFullscreen;
-        mAppImmersive = appImmersive;
         mTransientBarTypes = transientBarTypes;
     }
 
@@ -79,8 +79,8 @@
         dest.writeInt(mDisabledFlags2);
         dest.writeStrongBinder(mImeToken);
         dest.writeBoolean(mNavbarColorManagedByIme);
+        dest.writeInt(mBehavior);
         dest.writeBoolean(mAppFullscreen);
-        dest.writeBoolean(mAppImmersive);
         dest.writeIntArray(mTransientBarTypes);
     }
 
@@ -103,13 +103,13 @@
                     final int disabledFlags2 = source.readInt();
                     final IBinder imeToken = source.readStrongBinder();
                     final boolean navbarColorManagedByIme = source.readBoolean();
+                    final int behavior = source.readInt();
                     final boolean appFullscreen = source.readBoolean();
-                    final boolean appImmersive = source.readBoolean();
                     final int[] transientBarTypes = source.createIntArray();
                     return new RegisterStatusBarResult(icons, disabledFlags1, appearance,
                             appearanceRegions, imeWindowVis, imeBackDisposition, showImeSwitcher,
-                            disabledFlags2, imeToken, navbarColorManagedByIme, appFullscreen,
-                            appImmersive, transientBarTypes);
+                            disabledFlags2, imeToken, navbarColorManagedByIme, behavior,
+                            appFullscreen, transientBarTypes);
                 }
 
                 @Override
diff --git a/core/java/com/android/internal/util/LocationPermissionChecker.java b/core/java/com/android/internal/util/LocationPermissionChecker.java
index 59c0c00..d67bd7a 100644
--- a/core/java/com/android/internal/util/LocationPermissionChecker.java
+++ b/core/java/com/android/internal/util/LocationPermissionChecker.java
@@ -24,6 +24,7 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.location.LocationManager;
+import android.net.NetworkStack;
 import android.os.Binder;
 import android.os.Build;
 import android.os.UserHandle;
@@ -147,6 +148,13 @@
             int uid, @Nullable String message) {
         checkPackage(uid, pkgName);
 
+        // Apps with NETWORK_SETTINGS, NETWORK_SETUP_WIZARD, NETWORK_STACK & MAINLINE_NETWORK_STACK
+        // are granted a bypass.
+        if (checkNetworkSettingsPermission(uid) || checkNetworkSetupWizardPermission(uid)
+                || checkNetworkStackPermission(uid) || checkMainlineNetworkStackPermission(uid)) {
+            return SUCCEEDED;
+        }
+
         // Location mode must be enabled
         if (!isLocationModeEnabled()) {
             return ERROR_LOCATION_MODE_OFF;
@@ -259,4 +267,37 @@
         // We don't care about pid, pass in -1
         return mContext.checkPermission(permissionType, -1, uid);
     }
+
+    /**
+     * Returns true if the |uid| holds NETWORK_SETTINGS permission.
+     */
+    public boolean checkNetworkSettingsPermission(int uid) {
+        return getUidPermission(android.Manifest.permission.NETWORK_SETTINGS, uid)
+                == PackageManager.PERMISSION_GRANTED;
+    }
+
+    /**
+     * Returns true if the |uid| holds NETWORK_SETUP_WIZARD permission.
+     */
+    public boolean checkNetworkSetupWizardPermission(int uid) {
+        return getUidPermission(android.Manifest.permission.NETWORK_SETUP_WIZARD, uid)
+                == PackageManager.PERMISSION_GRANTED;
+    }
+
+    /**
+     * Returns true if the |uid| holds NETWORK_STACK permission.
+     */
+    public boolean checkNetworkStackPermission(int uid) {
+        return getUidPermission(android.Manifest.permission.NETWORK_STACK, uid)
+                == PackageManager.PERMISSION_GRANTED;
+    }
+
+    /**
+     * Returns true if the |uid| holds MAINLINE_NETWORK_STACK permission.
+     */
+    public boolean checkMainlineNetworkStackPermission(int uid) {
+        return getUidPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, uid)
+                == PackageManager.PERMISSION_GRANTED;
+    }
+
 }
diff --git a/core/jni/android_os_HwBlob.cpp b/core/jni/android_os_HwBlob.cpp
index 0fb2911..a9db91b 100644
--- a/core/jni/android_os_HwBlob.cpp
+++ b/core/jni/android_os_HwBlob.cpp
@@ -257,7 +257,17 @@
     // XXX Again cannot refer to gFields.constructID because InitClass may
     // not have been called yet.
 
-    return env->NewObject(clazz.get(), constructID, size);
+    // Cases:
+    // - this originates from another process (something so large should not fit
+    //   in the binder buffer, and it should be rejected by the binder driver)
+    // - if this is used in process, this code makes too many heap copies (in
+    //   order to retrofit HIDL's scatter-gather format to java types) to
+    //   justify passing such a large amount of data over this path. So the
+    //   alternative (updating the constructor and other code to accept other
+    //   types, should also probably not be taken in this case).
+    CHECK_LE(size, std::numeric_limits<jint>::max());
+
+    return env->NewObject(clazz.get(), constructID, static_cast<jint>(size));
 }
 
 }  // namespace android
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 2ff474b..4dc8121 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1784,7 +1784,7 @@
       heap_tagging_level = M_HEAP_TAGGING_LEVEL_NONE;
       break;
   }
-  android_mallopt(M_SET_HEAP_TAGGING_LEVEL, &heap_tagging_level, sizeof(heap_tagging_level));
+  mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, heap_tagging_level);
   // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART runtime.
   runtime_flags &= ~RuntimeFlags::MEMORY_TAG_LEVEL_MASK;
 
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index fa046c6..d3c2d31 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -626,6 +626,7 @@
         optional int32 target_uid = 1;
         optional int64 duration_ms = 2;
         optional string tag = 3;
+        optional int32 type = 4;
     }
     repeated PendingTempWhitelist pending_temp_whitelist = 26;
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 51fb264..253aece 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -617,6 +617,9 @@
     <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_UNAVAILABLE" />
     <protected-broadcast android:name="com.android.server.pm.DISABLE_QUIET_MODE_AFTER_UNLOCK" />
 
+    <protected-broadcast android:name="android.intent.action.PROFILE_ACCESSIBLE" />
+    <protected-broadcast android:name="android.intent.action.PROFILE_INACCESSIBLE" />
+
     <protected-broadcast android:name="com.android.server.retaildemo.ACTION_RESET_DEMO" />
 
     <protected-broadcast android:name="android.intent.action.DEVICE_LOCKED_CHANGED" />
@@ -2676,11 +2679,11 @@
          The app can check whether it has this authorization by calling
          {@link android.provider.Settings#canDrawOverlays
          Settings.canDrawOverlays()}.
-         <p>Protection level: signature|appop|installer|pre23|development|recents -->
+         <p>Protection level: signature|appop|preinstalled|pre23|development -->
     <permission android:name="android.permission.SYSTEM_ALERT_WINDOW"
         android:label="@string/permlab_systemAlertWindow"
         android:description="@string/permdesc_systemAlertWindow"
-        android:protectionLevel="signature|appop|installer|pre23|development|recents" />
+        android:protectionLevel="signature|appop|preinstalled|pre23|development" />
 
     <!-- @SystemApi @hide Allows an application to create windows using the type
          {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY},
@@ -3105,7 +3108,7 @@
     <!-- @SystemApi Allows an application to read system update info.
          @hide -->
     <permission android:name="android.permission.READ_SYSTEM_UPDATE_INFO"
-        android:protectionLevel="signature" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows the system to bind to an application's task services
          @hide -->
@@ -3160,6 +3163,11 @@
     <permission android:name="android.permission.CHANGE_OVERLAY_PACKAGES"
         android:protectionLevel="signature|privileged" />
 
+    <!-- Allows an application to set, update and remove the credential management app.
+         @hide -->
+    <permission android:name="android.permission.MANAGE_CREDENTIAL_MANAGEMENT_APP"
+        android:protectionLevel="signature" />
+
     <!-- ========================================= -->
     <!-- Permissions for special development tools -->
     <!-- ========================================= -->
@@ -3612,6 +3620,15 @@
     <permission android:name="android.permission.BIND_TRANSLATION_SERVICE"
                 android:protectionLevel="signature" />
 
+    <!-- @SystemApi Allows apps to use ui translation functions.
+         <p>Protection level: signature|privileged
+         <p> TODO(b/177703453): Restrict to a specific Role instead of allowing access to any
+         privileged app.
+         @hide Not for use by third-party applications.
+    -->
+    <permission android:name="android.permission.MANAGE_UI_TRANSLATION"
+                android:protectionLevel="signature|privileged" />
+
     <!-- Must be required by a android.service.contentsuggestions.ContentSuggestionsService,
          to ensure that only the system can bind to it.
          @SystemApi @hide This is not a third-party API (intended for OEMs and system apps).
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 4828f3f..bd017fd 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Inkomender beller-ID"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Uitgaande beller-ID"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"ID van gekoppelde lyn"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Beperking op ID van gekoppelde lyn"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Oproepaanstuur"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Net Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g>-oorkruis-SIM-oproepe"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nie aangestuur nie"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> na <xliff:g id="TIME_DELAY">{2}</xliff:g> sekondes"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 9d87ddc..4955e47 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"የገቢ ደዋይID"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"የወጪ ጥሪID"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"የተገናኘ መስመር መታወቂያ"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"የተገናኘ መስመር መታወቂያ ገደብ"</string>
     <string name="CfMmi" msgid="8390012691099787178">"ጥሪ ማስተላለፍ"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Wi-Fi ብቻ"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> የሲም መካከል የሚደረግ ጥሪ"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>፡አልተላለፈም"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>፡<xliff:g id="DIALING_NUMBER">{1}</xliff:g> ከ<xliff:g id="TIME_DELAY">{2}</xliff:g> ሰከንዶች በኋላ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 2a6d379..770c304 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -61,7 +61,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"معرف المتصل الوارد"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"معرف المتصل الصادر"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"معرّف الخط المتصل"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"تقييد معرّف الخط المتصل"</string>
     <string name="CfMmi" msgid="8390012691099787178">"إعادة توجيه المكالمة"</string>
@@ -152,8 +153,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"‏Wi-Fi فقط"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"‏<xliff:g id="SPN">%s</xliff:g> الاتصال عبر شرائح SIM"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: لم تتم إعادة التوجيه"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> بعد <xliff:g id="TIME_DELAY">{2}</xliff:g> ثانية"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index aab5906..2e23ee4 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"অন্তৰ্গামী কলাৰ আইডি"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"বহিৰ্গামী কলাৰ আইডি"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"সংযোজিত লাইন আইডি"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"সংযোজিত লাইন আইডিৰ সীমাবদ্ধতা"</string>
     <string name="CfMmi" msgid="8390012691099787178">"কল ফৰৱাৰ্ডিং"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"কোৱল ৱাই-ফাই"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> ক্ৰছ-ছিম কলিং"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ফৰৱাৰ্ড কৰা নহ\'ল"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> ছেকেণ্ডৰ পাছত"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index bcc9fe2..475fa7d 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Gələn çağrı kimliyi"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Gedən çağrı kimliyi"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Qoşulmuş Xətt ID"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Qoşulmuş Xətt ID Məhdudluğu"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Zəng yönləndirmə"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Yalnız Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> Çarpaz SİM Zəngi"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Yönləndirilmədi"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> saniyə sonra"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 7531077..6378045 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -58,7 +58,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Dolazni ID pozivaoca"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Odlazni ID pozivaoca"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"ID povezane linije"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Ograničenje ID-a povezane linije"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Preusmeravanje poziva"</string>
@@ -149,8 +150,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Samo WiFi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"Pozivi sa više SIM kartica za operatera <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nije prosleđeno"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> nakon <xliff:g id="TIME_DELAY">{2}</xliff:g> sekunde/i"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 93e0802..80c071c 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -59,7 +59,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Ідэнтыфікатар АВН"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Ідэнтыфікатар АВН"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Ідэнтыфікатар падлучанай лініі"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Абмежаванне ідэнтыфікатара падлучанай лініі"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Пераадрасацыя выкліку"</string>
@@ -150,8 +151,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Толькі Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> Тэлефанія паміж SIM-картамі"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: не пераадрасоўваецца"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> праз <xliff:g id="TIME_DELAY">{2}</xliff:g> с."</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 08cab8d..6dd7b6a6 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Идентификация на вх. обаждания"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Идентификация на изходящите повиквания"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Идентификация на свързаната линия"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Ограничение за идентификацията на свързаната линия"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Пренасочване на повиквания"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Само Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"Обаждания през друга SIM карта от <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Не е пренасочено"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> след <xliff:g id="TIME_DELAY">{2}</xliff:g> секунди"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index f3ad8da..ff9b003 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"আগত কলার আইডি"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"আউটগোয়িং কলার আইডি"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"সংযুক্ত লাইন ID"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"সংযুক্ত লাইন ID-র বিধিনিষেধ"</string>
     <string name="CfMmi" msgid="8390012691099787178">"কল ফরওয়ার্ড করা"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"শুধুমাত্র ওয়াই-ফাই"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> ক্রস সিম কল করা"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ফরওয়ার্ড করা হয়নি"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> সেকেন্ড পরে"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index d080d05..d2a4f7d 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -58,7 +58,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"ID dolaznog poziva"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"ID odlaznog poziva"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Identifikacija povezane linije"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Ograničenje identifikacije povezane linije"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Prosljeđivanje poziva"</string>
@@ -149,8 +150,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Samo WiFi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> – pozivanje na različitim SIM-ovima"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nije proslijeđen"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> za <xliff:g id="TIME_DELAY">{2}</xliff:g> sekundi"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index f7c27bc..47be220 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Identificador de trucada (trucada entrant)"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Identificador de trucada (trucada de sortida)"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Identificador de la línia connectada"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Restricció de l\'identificador de la línia connectada"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Desviació de trucades"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Només Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"Trucades entre targetes SIM de l\'operador <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: no s\'ha desviat"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> després de <xliff:g id="TIME_DELAY">{2}</xliff:g> segons"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 1639718..e7e4cc9 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -59,7 +59,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Příchozí ID volajícího"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Odchozí ID volajícího"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"ID připojené linky"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Omezení ID připojené linky"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Přesměrování hovorů"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 7fb2042..47416cf 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI-nummer"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Indgående opkalds-id"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Udgående opkalds-id"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Id for opkaldsmodtager"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Id for opkaldsmodtager er skjult"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Viderestilling af opkald"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Kun Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> Opkald på tværs af SIM-kort"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke viderestillet"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> efter <xliff:g id="TIME_DELAY">{2}</xliff:g> sekunder"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 2e443e8..54e9dfd 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Anrufer-ID für eingehenden Anruf"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Anrufer-ID für ausgehenden Anruf"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"ID der verbundenen Leitung"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Beschränkung für ID der verbundenen Leitung"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Rufweiterleitung"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index e056b98..b759be6 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Εισερχόμενη αναγνώριση κλήσης"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Εξερχόμενη αναγνώριση κλήσης"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Αναγνωριστικό συνδεδεμένης γραμμής"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Περιορισμός αναγνωριστικού συνδεδεμένης πρόσβασης"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Προώθηση κλήσεων"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Μόνο Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"Κλήση με πολλές SIM <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Δεν προωθήθηκε"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> μετά από <xliff:g id="TIME_DELAY">{2}</xliff:g> δευτερόλεπτα"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 88519df..7c7c178 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Incoming Caller ID"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Outgoing Caller ID"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Connected Line ID"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Connected Line ID Restriction"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Call forwarding"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Wi-Fi only"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> Cross-SIM calling"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Not forwarded"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> after <xliff:g id="TIME_DELAY">{2}</xliff:g> seconds"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 1baa7f9..0cbbb01 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Incoming Caller ID"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Outgoing Caller ID"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Connected Line ID"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Connected Line ID Restriction"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Call forwarding"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Wi-Fi only"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> Cross-SIM calling"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Not forwarded"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> after <xliff:g id="TIME_DELAY">{2}</xliff:g> seconds"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 687afae..e923d65 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Incoming Caller ID"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Outgoing Caller ID"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Connected Line ID"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Connected Line ID Restriction"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Call forwarding"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Wi-Fi only"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> Cross-SIM calling"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Not forwarded"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> after <xliff:g id="TIME_DELAY">{2}</xliff:g> seconds"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index db34264..6e17242 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Incoming Caller ID"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Outgoing Caller ID"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Connected Line ID"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Connected Line ID Restriction"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Call forwarding"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Wi-Fi only"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> Cross-SIM calling"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Not forwarded"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> after <xliff:g id="TIME_DELAY">{2}</xliff:g> seconds"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 7d1d04d..759fe01 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‏‏‏‎‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‎‏‎‎‎‎‎‎‎‏‏‏‏‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‏‎‎IMEI‎‏‎‎‏‎"</string>
     <string name="meid" msgid="3291227361605924674">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‏‎‏‎‏‏‎‎‏‏‎‎‏‎‎‏‏‏‎‏‏‎‎‏‎‎‎‎‎‎‏‏‏‎‎‏‎‎‎‏‎‎‏‏‎‏‏‏‎‏‎‎‎‎‏‎‎MEID‎‏‎‎‏‎"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‎‎‎‎‏‎‏‏‏‎‎‏‏‎‏‎‏‏‎‏‏‎‎‏‎‎‏‎‏‏‎‎‎‏‎‎‏‏‏‎‎‏‏‏‏‎‎‏‎‎‏‎‎‏‎‏‎Incoming Caller ID‎‏‎‎‏‎"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‏‎‎‎‏‎‎‎‎‏‎‏‎‎‏‎‏‏‎‏‏‎‏‎‏‎‎‏‎‎‏‎‎‎‏‏‏‏‎‎‏‏‏‎‏‎‎‎‏‎‏‎‏‎‎‎Outgoing Caller ID‎‏‎‎‏‎"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‏‏‏‎‏‏‎‏‎‎‏‎‏‏‏‏‏‎‏‎‎‎‎‎‎‏‎‏‏‎‎‎‎‎‏‎‎‏‎‏‏‎‎‏‏‎‏‏‏‎‎‏‏‎‎Connected Line ID‎‏‎‎‏‎"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‏‏‏‏‎‎‏‎‏‏‎‏‎‏‏‏‏‏‎‏‎‏‏‎‏‏‏‏‎‏‏‎‎‏‎‎‎‎‏‏‎‎‏‎‏‏‏‎‏‏‎‏‏‎‎Connected Line ID Restriction‎‏‎‎‏‎"</string>
     <string name="CfMmi" msgid="8390012691099787178">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‏‏‏‏‎‏‎‏‎‎‎‎‎‎‎‏‎‏‏‏‎‎‏‎‎‎‏‎‎‎‎‎‎‏‎‏‏‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‎Call forwarding‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 528f7b9..64bc3d1 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Identificador de llamadas entrantes"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Identificador de llamadas salientes"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"ID de línea conectada"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Restricción de ID de línea conectada"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Desvío de llamadas"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Solo Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"Llamadas entre tarjetas SIM de <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: no se ha remitido"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> después de <xliff:g id="TIME_DELAY">{2}</xliff:g> segundos"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 9c0ab18..08555e8 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"ID de emisor de llamada entrante"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"ID de emisor de llamada saliente"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"ID de línea conectada"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Restricción de ID de línea conectada"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Desvío de llamadas"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Solo Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"Llamadas entre tarjetas SIM de <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: No desviada"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> transcurridos <xliff:g id="TIME_DELAY">{2}</xliff:g> segundos"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 8de5734..4818589 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Sissetuleva kõne helistaja ID"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Väljuva kõne helistaja ID"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Ühendatud liini ID"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Ühendatud liini ID piiramine"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Kõnede suunamine"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Ainult WiFi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> – helistamine mitme SIM-kaardi kaudu"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: pole suunatud"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> sekundi pärast"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 5a944f3..39fc77c 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI zk."</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Sarrerako deien identifikazio-zerbitzua"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Irteerako deien identifikazio-zerbitzua"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Konektatutako linearen IDa"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Konektatutako linearen ID murriztapena"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Dei-desbideratzea"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Wifi-sarea soilik"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> operadorearen beste SIM txartel batetik deitzeko aukera"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ez da desbideratu"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> zenbakira <xliff:g id="TIME_DELAY">{2}</xliff:g> segundotan"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index be27d70..935d679 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"شناسه تماس‌گیرنده ورودی"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"شناسه تماس‌گیرنده خروجی"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"شناسه خط متصل"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"محدودیت شناسه خط متصل"</string>
     <string name="CfMmi" msgid="8390012691099787178">"هدایت تماس"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"‏فقط Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"تماس بین سیم‌کارت <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: هدایت نشده"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> پس از <xliff:g id="TIME_DELAY">{2}</xliff:g> ثانیه"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index dc2af5a..09f289a 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI-koodi"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Soittajan tunnus"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Soittajan tunnus"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Yhteyslinjan tunnus"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Yhteyslinjan tunnuksen rajoitus"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Soitonsiirto"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Vain Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"SIM-korttien väliset puhelut: <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ei siirretty"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> sekunnin päästä"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index c4bf3f7..6bedfca 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"Code IIEM"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Numéro de l\'appelant (entrant)"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Numéro de l\'appelant (sortant)"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Identifiant de la ligne connectée"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Restriction d\'identifiant de la ligne connectée"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Transfert d\'appel"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Wi-Fi seulement"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"Appels multiSIM avec <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : non transféré"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : <xliff:g id="DIALING_NUMBER">{1}</xliff:g> au bout de <xliff:g id="TIME_DELAY">{2}</xliff:g> secondes"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 998845f..d8edc5d 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"Code IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"Code MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Numéro de l\'appelant (entrant)"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Numéro de l\'appelant (sortant)"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Identifiant de la ligne connectée"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Restriction d\'identifiant de la ligne connectée"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Transfert d\'appel"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Wi-Fi uniquement"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"Appels par cartes SIM croisées <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : non transféré"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : <xliff:g id="DIALING_NUMBER">{1}</xliff:g> au bout de <xliff:g id="TIME_DELAY">{2}</xliff:g> secondes"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 8548506..76ab6ab 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Identificador de chamada entrante"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Identificador de chamada saínte"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"ID de liña conectada"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Restrición de ID de liña conectada"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Desvío de chamadas"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Só por wifi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"Chamadas doutra SIM a través desta (<xliff:g id="SPN">%s</xliff:g>)"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: non desviada"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> tras <xliff:g id="TIME_DELAY">{2}</xliff:g> segundos"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 4f27856..a591d31 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"આવનાર કૉલર ID"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"આઉટગોઇંગ કૉલર ID"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"કનેક્ટ કરેલ લાઇન ID"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"કનેક્ટ કરેલ લાઇન ID પ્રતિબંધ"</string>
     <string name="CfMmi" msgid="8390012691099787178">"કૉલ ફોર્વર્ડિંગ"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index f374b96..a094117 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"आईएमईआई"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"इनकमिंग कॉलर आईडी"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"आउटगोइंग कॉलर आईडी"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"कनेक्ट किया गया लाइन आईडी"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"कनेक्ट किया गया लाइन आईडी प्रतिबंध"</string>
     <string name="CfMmi" msgid="8390012691099787178">"कॉल आगे भेजना"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"केवल वाई-फ़ाई"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> क्रॉस सिम कॉलिंग"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: अग्रेषित नहीं किया गया"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> सेकंड के बाद"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 981fff4..aebab8c 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -58,7 +58,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"ID dolaznog pozivatelja"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"ID izlaznog pozivatelja"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"ID povezane linije"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Ograničenje ID-a povezane linije"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Preusmjeravanje poziva"</string>
@@ -149,8 +150,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Samo Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> Preusmjeravanje poziva na drugi SIM"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nije proslijeđeno"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> nakon <xliff:g id="TIME_DELAY">{2}</xliff:g> s"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 09ee61a..efdf842 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Beérkező hívóazonosító"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Kimenő hívóazonosító"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Összekapcsolt sorazonosító"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Összekapcsolt sorazonosító korlátozása"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Hívásátirányítás"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Csak Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> SIM-eken keresztüli hívás"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: nincs átirányítva"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> másodperc után"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 0539da1..29803b8 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Մուտքային զանգողի ID"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Ելքային զանգողի ID"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Կապված տողի ID"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Կապված տողի ID-ի սահմանափակում"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Զանգի վերահասցեավորում"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Միայն Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> SIM քարտերով խաչաձև զանգեր"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>. Չի վերահասցեավորվել"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>. <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>. <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> վայրկյանից"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 969145f..510621b 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Nomor Penelepon Masuk"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Nomor Penelepon Keluar"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"ID Saluran yang Tersambung"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Batasan ID Saluran yang Tersambung"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Penerusan panggilan"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Khusus Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"Panggilan Lintas-SIM <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Tidak diteruskan"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> setelah <xliff:g id="TIME_DELAY">{2}</xliff:g> detik"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 7c7c4eb..802feeeb 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Númerabirting innhringinga"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Númerabirting úthringinga"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Auðkenni tengdrar línu"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Auðkennistakmörkun tengdrar línu"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Símtalsflutningur"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Wi-Fi eingöngu"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> Skipt á milli SIM-korta"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ekki áframsent"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> eftir <xliff:g id="TIME_DELAY">{2}</xliff:g> sekúndur"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 1703493..2c01776 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"ID chiamante in entrata"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"ID chiamante in uscita"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"ID linea connessa"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Limitazione ID linea connessa"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Deviazione chiamate"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Solo Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"Chiamate tramite più SIM <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: inoltro non effettuato"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g><xliff:g id="DIALING_NUMBER">{1}</xliff:g> dopo <xliff:g id="TIME_DELAY">{2}</xliff:g> secondi"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 8a73d70..2bdabc8 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -59,7 +59,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"זיהוי מתקשר של שיחה נכנסת"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"זיהוי מתקשר בשיחה יוצאת"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"מזהה של קו מחובר"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"הגבלה של מזהה קו מחובר"</string>
     <string name="CfMmi" msgid="8390012691099787178">"העברת שיחות"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 263c87e..cf493c0 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"着信時の発信者番号"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"発信者番号"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"接続回線ID"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"接続回線IDの制限"</string>
     <string name="CfMmi" msgid="8390012691099787178">"着信転送"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Wi-Fiのみ"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> Cross-SIM 通話"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:転送できません"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="DIALING_NUMBER">{1}</xliff:g> (<xliff:g id="TIME_DELAY">{2}</xliff:g>秒後)"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 7b616b4..9de08bc 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"შემომავალი ზარის აბონენტის ID"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"გამავალი მრეკავის ID"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"დაუკავშირდა Line ID-ს"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"დაუკავშირდა Line ID Restriction-ს"</string>
     <string name="CfMmi" msgid="8390012691099787178">"ზარის გადამისამართება"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"მხოლოდ Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> SIM-თაშორისი დარეკვა"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: არ არის გადამისამართებული"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> წამის შემდეგ"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 96cf902..f38be01 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI (Халықаралық мобильдік құрылғы анықтағышы)"</string>
     <string name="meid" msgid="3291227361605924674">"MEID (ұялы құрылғы анықтағыш)"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Келген қоңырау шалушының жеке анықтағышы"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Шыққан қоңырау шалушының жеке анықтағышы"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Қосылған желі идентификаторы"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Қосылған желі идентификаторын шектеу"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Қоңырауды басқа нөмірге бағыттау"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Тек Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> SIM карталары арасында қоңырау шалу"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Басқа нөмірге бағытталмады"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>  <xliff:g id="TIME_DELAY">{2}</xliff:g> секундтан кейін"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 8db1191..2a70449 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"លេខ​សម្គាល់​អ្នក​ហៅ​​ចូល​"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"លេខ​សម្គាល់​អ្នក​ហៅ​ចេញ"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"បាន​ភ្ជាប់​លេខ​សម្គាល់​បន្ទាត់"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"បាន​ភ្ជាប់​ការ​ដាក់កម្រិត​លេខ​សម្គាល់​បន្ទាត់"</string>
     <string name="CfMmi" msgid="8390012691099787178">"បញ្ជូន​ការ​ហៅ​បន្ត"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Wi-Fi តែប៉ុណ្ណោះ"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"ការហៅទូរសព្ទ​ឆ្លងស៊ីម​តាមរយៈ <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> ៖ មិន​បាន​បញ្ជូន​បន្ត"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> បន្ទាប់​ពី <xliff:g id="TIME_DELAY">{2}</xliff:g> វិនាទី"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 8bd2f49..9fc9f36 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"ಒಳಬರುವ ಕರೆಮಾಡುವವರ ID"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"ಹೊರಹೋಗುವ ಕರೆಮಾಡುವವರ ID"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"ಲೈನ್ ID ಗೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"ಲೈನ್ ID ನಿರ್ಬಂಧನೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ"</string>
     <string name="CfMmi" msgid="8390012691099787178">"ಕರೆಯ ರವಾನೆ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index d812de9..fd81606b 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"발신자 번호"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"내 발신 번호"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"환승편 ID"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"환승편 ID 제한"</string>
     <string name="CfMmi" msgid="8390012691099787178">"착신전환"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Wi-Fi에서만"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> Cross SIM 통화"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: 착신전환 안됨"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g><xliff:g id="TIME_DELAY">{2}</xliff:g>초 후"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index acd46ce..612193c 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Кирүүчү номурду аныктоо"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Чыгуучу номурду аныктоо"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Туташкан линия ID-си"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Туташкан линия ID-син Чектөө"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Башка номерге багыттоо"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Wi-Fi гана"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> SIM карталарынан кайчылаш чалуу"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Багытталган эмес"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> секунддан кийин"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index ceee938..760d920 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"ໝາຍເລກຜູ່ໂທເຂົ້າ"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"ໝາຍເລກຜູ່ໂທອອກ"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Line ID ທີ່​ເຊື່ອມ​ໂຍງ"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"​ຂໍ້​ຈຳ​ກັດ Line ID ທີ່​ເຊື່ອມ​ໂຍງ"</string>
     <string name="CfMmi" msgid="8390012691099787178">"ການໂອນສາຍ"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Wi​-Fi ເທົ່າ​ນັ້ນ"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> ການໂທຂ້າມຊິມ"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ບໍ່ຖືກສົ່ງຕໍ່"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> ຫຼັງຈາກ <xliff:g id="TIME_DELAY">{2}</xliff:g> ວິນາທີ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index f260ebe..da18b18 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -59,7 +59,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Įeinančio skambintojo ID"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Išeinančio skambintojo ID"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Prijungtos eilutės ID"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Prijungtos eilutės ID apribojimas"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Skambučio peradresavimas"</string>
@@ -150,8 +151,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Tik „Wi-Fi“"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"„<xliff:g id="SPN">%s</xliff:g>“: skambinimas per SIM korteles"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: neperadresuota"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> po <xliff:g id="TIME_DELAY">{2}</xliff:g> sek."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 5fe3733..4fdd570f 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -58,7 +58,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Ienākošā zvana zvanītāja ID"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Izejošā zvana zvanītāja ID"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Saistītās līnijas ID"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Saistītās līnijas ID ierobežojums"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Zvanu pāradresācija"</string>
@@ -149,8 +150,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Tikai Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g>: zvanīšana, izmantojot dažādas SIM kartes"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: nav pāradresēts"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> pēc <xliff:g id="TIME_DELAY">{2}</xliff:g> sekundes(-ēm)"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index b7536b4..b18ce23 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"ID на дојдовен повикувач"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"ID на појдовен повикувач"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"ID на поврзана линија"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Забрана на ID на поврзана линија"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Проследување повик"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Само Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"Повици преку повеќе SIM-картички на <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: не е препратено"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> по <xliff:g id="TIME_DELAY">{2}</xliff:g> секунди"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 5d18f82..d21ab5a 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"ഇൻകമിംഗ് വിളിച്ച നമ്പർ"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"ഔട്ട്ഗോയിംഗ് വിളിച്ച നമ്പർ"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"കണക്‌റ്റുചെയ്‌തിരിക്കുന്ന ലൈൻ ഐഡി"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"കണക്‌റ്റുചെയ്‌തിരിക്കുന്ന ലൈൻ ഐഡി നിയന്ത്രണം"</string>
     <string name="CfMmi" msgid="8390012691099787178">"കോൾ ഫോർവേഡിംഗ്"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"വൈഫൈ മാത്രം"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> ക്രോസ് സിം കോളിംഗ്"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: കൈമാറിയില്ല"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="TIME_DELAY">{2}</xliff:g> നിമിഷത്തിനുശേഷം <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 4b1b1b8..778a15b 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Дуудлага хийгчийн ID"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Гарч байгаа дуудлага хийгчийн ID"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Холбогдсон шугамын ID"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Холбогдсон шугамын ID Хязгаарлалт"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Дуудлага дамжуулах"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Зөвхөн Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> SIM хоорондын дуудлага"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: дамжуулагдаагүй"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> секундын дараа"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index a5577c8..dc5175b 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"येणारा कॉलर आयडी"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"केला जाणारा कॉलर आयडी"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"कनेक्ट केलेला रेखा आयडी"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"कनेक्ट केलेला रेखा आयडी प्रतिबंध"</string>
     <string name="CfMmi" msgid="8390012691099787178">"कॉल फॉरवर्डिंग"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index afd49ee..a14ea62 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"ID Pemanggil Masuk"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"ID Pemanggil Keluar"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"ID Laluan yang disambungkan"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Sekatan ID Laluan yang disambungkan"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Pemajuan panggilan"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 657a1d3..f768d17 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEIDနံပါတ်"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"အဝင်ခေါ်ဆိုမှုID"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"အထွက်ခေါ်ဆိုခြင်းအိုင်ဒီ"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"လိုင်း ID ချိတ်ဆက်သည်"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"လိုင်း ID ချိတ်ဆက်မှု ကန့်သတ်ချက်များ"</string>
     <string name="CfMmi" msgid="8390012691099787178">"အဝင်ခေါ်ဆိုမှုအား ထပ်ဆင့်ပို့ခြင်း"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"ကြိုးမဲ့အင်တာနက် သာလျှင်"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> Cross-SIM ခေါ်ဆိုမှု"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ထပ်ဆင့်မပို့နိုင်ပါ"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> နောက် <xliff:g id="TIME_DELAY">{2}</xliff:g> စက္ကန့်"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 8eed7f5..c6831a8 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Inngående nummervisning"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Utgående nummervisning"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Tilkoblet linje-ID"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Begrensning for tilkoblet linje-ID"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Viderekobling"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Bare Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"Ringing mellom SIM-kort med <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke viderekoblet"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> etter <xliff:g id="TIME_DELAY">{2}</xliff:g> sekunder"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index b813d9e..ff0b00e 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"आगमन कलर ID"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"बाहिरिने कलर ID"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"लाइन ID जोडियो"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"जोडिएको लाइन ID प्रतिबन्ध"</string>
     <string name="CfMmi" msgid="8390012691099787178">"कल अगाडि बढाउँदै"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Wi-Fi मात्र"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> क्रस SIM कलिङ"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: अगाडि पठाइएको छैन"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> पछि <xliff:g id="TIME_DELAY">{2}</xliff:g> सेकेन्ड"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 9ef66df..4ada7a2 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Inkomende beller-ID"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Uitgaande beller-ID"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"ID van verbonden lijn"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Beperking voor ID van verbonden lijn"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Gesprek doorschakelen"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Alleen wifi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"Cross-sim-bellen van <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: niet doorgeschakeld"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> na <xliff:g id="TIME_DELAY">{2}</xliff:g> seconden"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index a2c3759..54e064d 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"ଇନକମିଙ୍ଗ କଲର୍ ଆଇଡି"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"ଆଉଟଗୋଇଙ୍ଗ୍ କଲର୍ ଆଇଡି"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"ସଂଯୁକ୍ତ ଲାଇନ୍ ID"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"ସଂଯୁକ୍ତ ଲାଇନ୍ ID କଟକଣା"</string>
     <string name="CfMmi" msgid="8390012691099787178">"କଲ୍‌ ଫରୱାର୍ଡିଂ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 3ceb626..804b77d 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"ਇਨਕਮਿੰਗ ਕਾਲਰ ਆਈ.ਡੀ."</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"ਆਊਟਗੋਇੰਗ ਕਾਲਰ ਆਈ.ਡੀ."</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"ਕਨੈਕਟ ਕੀਤੀ ਲਾਈਨ ਆਈ.ਡੀ."</string>
     <string name="ColrMmi" msgid="5889782479745764278">"ਕਨੈਕਟ ਕੀਤੀ ਲਾਈਨ ਆਈ.ਡੀ. ਪ੍ਰਤਿਬੰਧ"</string>
     <string name="CfMmi" msgid="8390012691099787178">"ਕਾਲ ਫਾਰਵਰਡਿੰਗ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 6849333..8d669c4 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -59,7 +59,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"ID rozmówcy przy połączeniach przychodzących"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"ID rozmówcy przy połączeniach wychodzących"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Identyfikator połączonej linii"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Ograniczenie identyfikatora połączonej linii"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Przekierowanie połączeń"</string>
@@ -150,8 +151,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Tylko Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"Połączenia przez różne karty SIM z <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: nieprzekierowane"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> po <xliff:g id="TIME_DELAY">{2}</xliff:g> sekundach"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 84e5a73..9837b88 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Identificador de chamadas recebidas"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Identificador de chamadas realizadas"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"ID de linha conectada"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Restrição de ID de linha conectada"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Encaminhamento de chamada"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Somente Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"Chamadas entre chips da <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não encaminhado"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> após <xliff:g id="TIME_DELAY">{2}</xliff:g> segundos"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 507d759..ef7ee98 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"ID do Autor da Chamada"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"ID do autor da chamada efetuada"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"ID de linha ligada"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Restrição de ID de linha ligada"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Encaminhamento de chamadas"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 84e5a73..9837b88 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Identificador de chamadas recebidas"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Identificador de chamadas realizadas"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"ID de linha conectada"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Restrição de ID de linha conectada"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Encaminhamento de chamada"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Somente Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"Chamadas entre chips da <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não encaminhado"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> após <xliff:g id="TIME_DELAY">{2}</xliff:g> segundos"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 4b1d3ac..68dad1c 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -58,7 +58,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"ID apelant de primire"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"ID apelant"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"ID-ul liniei conectate"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Restricționarea ID-ului liniei conectate"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Redirecționarea apelurilor"</string>
@@ -149,8 +150,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Numai Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"Apelare pe mai multe carduri SIM <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: neredirecționată"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> după <xliff:g id="TIME_DELAY">{2}</xliff:g>   secunde"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 1588c2b..03383f9 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -59,7 +59,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Идентификация вызывающего абонента"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Идентификация звонящего абонента"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Идентификатор подключенной линии"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Ограничение идентификатора подключенной линии"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Переадресация вызовов"</string>
@@ -150,8 +151,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Только Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"Перекрестная работа SIM-карт от \"<xliff:g id="SPN">%s</xliff:g>\""</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: не переадресовано"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> через <xliff:g id="TIME_DELAY">{2}</xliff:g> с."</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index db0d5ad..cfa9bf1 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"පැමිණෙන අමතන්නාගේ ID"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"පිටතට යන අමතන්නාගේ ID"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"සම්බන්ධ කළ Line ID"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"සම්බන්ධ කළ Line ID සීමා කිරීම්"</string>
     <string name="CfMmi" msgid="8390012691099787178">"ඇමතුම ඉදිරියට යැවීම"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Wi-Fi පමණයි"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> හරස් SIM ඇමතුම"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ඉදිරියට නොයවන ලදි"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: තත්පර <xliff:g id="TIME_DELAY">{2}</xliff:g> ට පසුව <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 546a64b..f8dfc26 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -59,7 +59,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Prichádzajúca identifikácia volajúceho"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Odchádzajúca identifikácia volajúceho"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"ID pripojenej linky"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Obmedzenie ID pripojenej linky"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Presmerovanie hovorov"</string>
@@ -150,8 +151,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Len Wi‑Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> Volanie naprieč SIM kartami"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nepresmerované"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> po <xliff:g id="TIME_DELAY">{2}</xliff:g> s"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index a15676d..4a5c5da 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -59,7 +59,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"ID dohodnega klicatelja"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"ID odhodnega klicatelja"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"ID povezane linije"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Omejitev ID-ja povezane linije"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Preusmerjanje klicev"</string>
@@ -150,8 +151,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Samo Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"Klicanje ne glede na kartico SIM operaterja <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ni posredovano"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> po toliko sekundah: <xliff:g id="TIME_DELAY">{2}</xliff:g>"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index cc694fa..5ee9031 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"ID-ja e telefonuesit hyrës"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"ID-ja e telefonuesit në dalje"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"ID-ja e linjës së lidhur"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Kufizimi i ID-së së linjës së lidhur"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Transferimi i telefonatave"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 5cadfd5..a430d56 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -58,7 +58,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Долазни ИД позиваоца"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Одлазни ИД позиваоца"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"ИД повезане линије"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Ограничење ИД-а повезане линије"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Преусмеравање позива"</string>
@@ -149,8 +150,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Само WiFi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"Позиви са више SIM картица за оператера <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Није прослеђено"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> након <xliff:g id="TIME_DELAY">{2}</xliff:g> секунде/и"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index bba8700..186a78a 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI-kod"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Nummerpresentatör för inkommande samtal"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Nummerpresentatör för utgående samtal"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Visning av uppkopplat nummer"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Blockera visning av uppkopplat nummer"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Vidarekoppla samtal"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Endast Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> – samtal mellan SIM-kort"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Vidarebefordras inte"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g><xliff:g id="DIALING_NUMBER">{1}</xliff:g> efter <xliff:g id="TIME_DELAY">{2}</xliff:g> sekunder"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 3525ceb..cf9496d 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Kitambulisho cha Mpigaji wa Simu Inayoingia"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"ID ya Mpigaji simu Inayotoka nje"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Kitambulisho cha Mstari Uliounganishwa"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Kizuizi cha Kitambulisho cha Mstari Uliounganishwa"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Kusambaza simu"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Wi-Fi pekee"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> Kipengele cha Kupiga Simu Kupitia SIM Tofauti"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Haijatumiwa mwingine"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> baada ya sekunde <xliff:g id="TIME_DELAY">{2}</xliff:g>"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 61eac81..f3e5f91 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"உள்வரும் அழைப்பாளர் ஐடி"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"வெளிசெல்லும் அழைப்பாளர் ஐடி"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"இணைக்கப்பட்ட லைன் ஐடி"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"இணைக்கப்பட்ட லைன் ஐடியை வரம்பிடல்"</string>
     <string name="CfMmi" msgid="8390012691099787178">"அழைப்பு திருப்பிவிடுதல்"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"வைஃபை மட்டும்"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> கிராஸ்-சிம் அழைப்பு"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: பகிரப்படவில்லை"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="TIME_DELAY">{2}</xliff:g> வினாடிகளுக்குப் பிறகு <xliff:g id="DIALING_NUMBER">{1}</xliff:g> ஐப் பகிர்"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 666e980..2687aa1 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"ఇన్‌కమింగ్ కాలర్ ID"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"అవుట్‌గోయింగ్ కాలర్ ID"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"కనెక్ట్ చేయబడిన పంక్తి ID"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"కనెక్ట్ చేయబడిన పంక్తి ID నియంత్రణ"</string>
     <string name="CfMmi" msgid="8390012691099787178">"కాల్ ఫార్వర్డింగ్"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Wi-Fi మాత్రమే"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> క్రాస్-SIM కాలింగ్"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ఫార్వార్డ్ చేయబడలేదు"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="TIME_DELAY">{2}</xliff:g> సెకన్ల తర్వాత <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 5c6b7df..01ffd62 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"หมายเลขผู้โทรเข้า"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"หมายเลขผู้โทรออก"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"รหัสสายที่เชื่อมต่อ"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"ข้อจำกัดรหัสสายที่เชื่อมต่อ"</string>
     <string name="CfMmi" msgid="8390012691099787178">"การโอนสาย"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Wi-Fi เท่านั้น"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"การโทรข้ามซิม <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ไม่ได้โอนสาย"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> หลังผ่านไป <xliff:g id="TIME_DELAY">{2}</xliff:g> วินาที"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index d27757c..40968eb 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Papasok na Caller ID"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Papalabas na Caller ID"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Connected Line ID"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Paghihigpit sa Connected Line ID"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Pagpapasa ng tawag"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Wi-Fi lang"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"Cross-SIM na Pagtawag sa <xliff:g id="SPN">%s</xliff:g>"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Hindi naipasa"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> pagkatapos ng <xliff:g id="TIME_DELAY">{2}</xliff:g> (na) segundo"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 6c5ea97..342ff20 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Gelen Çağrı Kimliği"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Giden Çağrı Kimliği"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Bağlanılan Hat Kimliği"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Bağlanılan Hat Kimliğini Kısıtlama"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Çağrı yönlendirme"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Yalnızca kablosuz"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> Çapraz SIM Araması"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Yönlendirilmedi"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="TIME_DELAY">{2}</xliff:g> saniye sonra <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 6ae2e8e..cf2c6f1 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -59,7 +59,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Вхідн. ід. абонента"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Вихід. ід. абонента"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Ідентифікатор під’єднаної лінії"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Обмеження ідентифікатора під’єднаної лінії"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Переадресація виклику"</string>
@@ -150,8 +151,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Лише Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> – виклики між SIM-картами"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: не переслано"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> після <xliff:g id="TIME_DELAY">{2}</xliff:g> сек."</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index ae7f801..8f54c27 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"‏ان کمنگ کالر ID"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"‏آؤٹ گوئنگ کالر ID"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"‏منسلک لائن ID"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"‏منسلک لائن ID کی پابندی"</string>
     <string name="CfMmi" msgid="8390012691099787178">"کال فارورڈنگ"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 9bfb68f..a8bc4ba 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Kiruvchi raqami"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Chiquvchi raqami"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"Qo‘ng‘iroq qiluvchining raqami"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Qo‘ng‘iroq qiluvchining raqamini cheklash"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Chaqiruvlarni uzatish"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Faqat Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> Umumiy sim chaqiruvlar"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Yo‘naltirilmadi"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>  <xliff:g id="TIME_DELAY">{2}</xliff:g> soniyadan so‘ng"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index e11291c..0af241e 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Số gọi đến"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"Số gọi đi"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"ID đường kết nối"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Giới hạn ID đường kết nối"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Chuyển tiếp cuộc gọi"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Chỉ Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> Gọi bằng nhiều SIM"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Không được chuyển tiếp"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> sau <xliff:g id="TIME_DELAY">{2}</xliff:g> giây"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 6940140..4503305 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"来电显示"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"本机号码"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"连接的线路ID"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"连接的线路ID限制"</string>
     <string name="CfMmi" msgid="8390012691099787178">"来电转接"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"仅限 WLAN"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> 跨 SIM 卡通话"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:无法转接"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="TIME_DELAY">{2}</xliff:g>秒后<xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 1955b31..92b007c 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"來電顯示"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"本機號碼"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"連接線識別功能"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"連接線識別限制"</string>
     <string name="CfMmi" msgid="8390012691099787178">"來電轉駁"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"只限 Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> 跨 SIM 卡通話"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:尚未轉接"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> 於 <xliff:g id="TIME_DELAY">{2}</xliff:g> 秒後轉接"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index b95974d..df2d5ea 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"來電顯示"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"本機號碼"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"連接的線路 ID"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"連接的線路 ID 限制"</string>
     <string name="CfMmi" msgid="8390012691099787178">"來電轉接"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"只限 Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"「<xliff:g id="SPN">%s</xliff:g>」跨 SIM 卡通話"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:未轉接"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="TIME_DELAY">{2}</xliff:g> 秒後 <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 58607f0..3f2d547 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -57,7 +57,8 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"I-ID Yocingo Olungenayo"</string>
-    <string name="ClirMmi" msgid="4702929460236547156">"I-ID Yomshayeli Ephumayo"</string>
+    <!-- no translation found for ClirMmi (6752346475055446417) -->
+    <skip />
     <string name="ColpMmi" msgid="4736462893284419302">"I-ID yomugqa exhumekile"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"I-ID yomugqa oxhumekile ikhawulelwe"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Ukudlulisa ikholi"</string>
@@ -148,8 +149,7 @@
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"I-Wi-Fi kuphela"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
-    <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
-    <skip />
+    <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g>Ukwenza ikholi kwe-Cross Sim"</string>
     <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Akudlulisiwe"</string>
     <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> emuva kwamasekhondi angu-<xliff:g id="TIME_DELAY">{2}</xliff:g>"</string>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 0185714..bb26655 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2486,7 +2486,8 @@
         <attr name="singleUser" />
         <attr name="directBootAware" />
         <attr name="visibleToInstantApps" />
-        <!-- The code for this component is located in the given split. -->
+        <!-- The code for this component is located in the given split.
+             @deprecated Do not use it. This is not supported. -->
         <attr name="splitName" />
     </declare-styleable>
 
@@ -2602,7 +2603,8 @@
              must also be {@link android.R.attr#exported} if this flag is set. -->
         <attr name="externalService" format="boolean" />
         <attr name="visibleToInstantApps" />
-        <!-- The code for this component is located in the given split. -->
+        <!-- The code for this component is located in the given split.
+             @deprecated Do not use it. This is not supported. -->
         <attr name="splitName" />
         <!-- If true, and this is an {@link android.R.attr#isolatedProcess} service, the service
              will be spawned from an Application Zygote, instead of the regular Zygote.
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 1845faa..272e130 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -58,6 +58,7 @@
         <item><xliff:g id="id">@string/status_bar_hotspot</xliff:g></item>
         <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_battery</xliff:g></item>
         <item><xliff:g id="id">@string/status_bar_sensors_off</xliff:g></item>
     </string-array>
@@ -94,6 +95,7 @@
     <string translatable="false" name="status_bar_microphone">microphone</string>
     <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_sensors_off">sensors_off</string>
     <string translatable="false" name="status_bar_screen_record">screen_record</string>
 
@@ -991,6 +993,11 @@
     <!-- Time to wait while a button is pressed before triggering a very long press. -->
     <integer name="config_veryLongPressTimeout">3500</integer>
 
+    <!-- Time to wait before sending a HOME intent when waking up from power/home button.
+         (0 - do not send HOME intent on wakeup)
+    -->
+    <integer name="config_wakeUpToLastStateTimeoutMillis">0</integer>
+
     <!-- Package name for default keyguard appwidget [DO NOT TRANSLATE] -->
     <string name="widget_default_package_name" translatable="false"></string>
 
@@ -4610,4 +4617,9 @@
          If omitted, image editing will not be offered via Chooser.
          This name is in the ComponentName flattened format (package/class) [DO NOT TRANSLATE]  -->
     <string name="config_systemImageEditor" translatable="false"></string>
+
+    <!-- Whether to force WindowOrientationListener to keep listening to its sensor, even when
+         dreaming. This allows the AoD to rotate on devices without a wake device_orientation
+         sensor. Note that this flag should only be enabled for development/testing use. -->
+    <bool name="config_forceOrientationListenerEnabledWhileDreaming">false</bool>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c72a0cd..0c86905 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -438,6 +438,7 @@
   <java-symbol type="integer" name="config_veryLongPressTimeout" />
   <java-symbol type="integer" name="config_longPressOnBackBehavior" />
   <java-symbol type="bool" name="config_allowStartActivityForLongPressOnPowerInSetup" />
+  <java-symbol type="integer" name="config_wakeUpToLastStateTimeoutMillis" />
   <java-symbol type="integer" name="config_lowMemoryKillerMinFreeKbytesAdjust" />
   <java-symbol type="integer" name="config_lowMemoryKillerMinFreeKbytesAbsolute" />
   <java-symbol type="integer" name="config_max_pan_devices" />
@@ -2947,6 +2948,7 @@
   <java-symbol type="string" name="status_bar_secure" />
   <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_mobile" />
   <java-symbol type="string" name="status_bar_ethernet" />
   <java-symbol type="string" name="status_bar_vpn" />
@@ -4146,4 +4148,6 @@
   <java-symbol type="bool" name="config_attachNavBarToAppDuringTransition" />
 
   <java-symbol type="bool" name="config_enableBackSound" />
+
+  <java-symbol type="bool" name="config_forceOrientationListenerEnabledWhileDreaming" />
 </resources>
diff --git a/core/tests/coretests/src/android/content/OWNERS b/core/tests/coretests/src/android/content/OWNERS
index 696aa11..912db1e 100644
--- a/core/tests/coretests/src/android/content/OWNERS
+++ b/core/tests/coretests/src/android/content/OWNERS
@@ -1,4 +1,3 @@
 per-file ContextTest.java = file:/services/core/java/com/android/server/wm/OWNERS
 per-file *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS
-per-file AppSearchPersonTest.java = file:/core/java/android/content/pm/SHORTCUT_OWNERS
 per-file *Launcher* = file:/core/java/android/content/pm/LAUNCHER_OWNERS
diff --git a/core/tests/coretests/src/android/content/pm/AppSearchPersonTest.java b/core/tests/coretests/src/android/content/pm/AppSearchPersonTest.java
new file mode 100644
index 0000000..1ff88f7
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/AppSearchPersonTest.java
@@ -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.content.pm;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.Person;
+
+import org.junit.Test;
+
+public class AppSearchPersonTest {
+
+    @Test
+    public void testBuildPersonAndGetValue() {
+        final String name = "name";
+        final String key = "key";
+        final String uri = "name:name";
+
+        final Person person = new AppSearchPerson.Builder(uri)
+                .setName(name)
+                .setKey(key)
+                .setIsBot(true)
+                .setIsImportant(false)
+                .build()
+                .toPerson();
+
+        assertThat(person.getName()).isEqualTo(name);
+        assertThat(person.getKey()).isEqualTo(key);
+        assertThat(person.getUri()).isEqualTo(uri);
+        assertThat(person.isBot()).isTrue();
+        assertThat(person.isImportant()).isFalse();
+    }
+}
diff --git a/core/tests/coretests/src/android/content/pm/AppSearchShortcutInfoTest.java b/core/tests/coretests/src/android/content/pm/AppSearchShortcutInfoTest.java
new file mode 100644
index 0000000..da92e69
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/AppSearchShortcutInfoTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.Person;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.util.ArraySet;
+
+import org.junit.Test;
+
+import java.util.Set;
+
+public class AppSearchShortcutInfoTest {
+
+    @Test
+    public void testBuildShortcutAndGetValue() {
+        final String category =
+                "android.app.stubs.SHARE_SHORTCUT_CATEGORY";
+        final String id = "shareShortcut";
+        final String shortcutIconResName = "shortcut";
+        final ComponentName activity = new ComponentName("xxx", "s");
+        final Person person = new Person.Builder()
+                .setBot(false)
+                .setName("BubbleBot")
+                .setImportant(true)
+                .build();
+
+        final Set<String> categorySet = new ArraySet<>();
+        categorySet.add(category);
+        final Intent shortcutIntent = new Intent(Intent.ACTION_VIEW);
+        final ShortcutInfo shortcut = new AppSearchShortcutInfo.Builder(id)
+                .setActivity(activity)
+                .setText(id)
+                .setIconResName(shortcutIconResName)
+                .setIntent(shortcutIntent)
+                .setPerson(person)
+                .setCategories(categorySet)
+                .setFlags(ShortcutInfo.FLAG_LONG_LIVED)
+                .build()
+                .toShortcutInfo();
+
+        assertThat(shortcut.getId()).isEqualTo(id);
+        assertThat(shortcut.getShortLabel()).isEqualTo(id);
+        assertThat(shortcut.getIconResName()).isEqualTo(shortcutIconResName);
+        assertThat(shortcut.getIntent().toString()).isEqualTo(shortcut.toString());
+        assertThat(shortcut.getPersons().length).isEqualTo(1);
+        assertThat(shortcut.getPersons()[0]).isEqualTo(person);
+        assertThat(shortcut.getCategories()).isEqualTo(categorySet);
+        assertThat(shortcut.getFlags()).isEqualTo(ShortcutInfo.FLAG_LONG_LIVED);
+        assertThat(shortcut.getActivity()).isEqualTo(activity);
+    }
+}
diff --git a/core/tests/coretests/src/android/content/pm/OWNERS b/core/tests/coretests/src/android/content/pm/OWNERS
new file mode 100644
index 0000000..711f5f0
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/OWNERS
@@ -0,0 +1,2 @@
+per-file AppSearchPersonTest.java = file:/core/java/android/content/pm/SHORTCUT_OWNERS
+
diff --git a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
index 05ff218..65ea2a8 100644
--- a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
+++ b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
@@ -21,6 +21,8 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.AssetManager;
 import android.graphics.fonts.FontCustomizationParser;
@@ -44,11 +46,12 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.StandardCopyOption;
+import java.util.HashMap;
 import java.util.Locale;
+import java.util.Map;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
@@ -137,23 +140,55 @@
         }
     }
 
-    private static void buildSystemFallback(String xml,
-            FontCustomizationParser.Result oemCustomization, ArrayMap<String, Typeface> fontMap,
-            ArrayMap<String, FontFamily[]> fallbackMap) {
+    private static void buildSystemFallback(
+            @NonNull String xml,
+            @Nullable String oemXml,
+            @NonNull ArrayMap<String, Typeface> outFontMap,
+            @NonNull ArrayMap<String, FontFamily[]> outFallbackMap) {
         try (FileOutputStream fos = new FileOutputStream(TEST_FONTS_XML)) {
-            fos.write(xml.getBytes(Charset.forName("UTF-8")));
+            fos.write(xml.getBytes(StandardCharsets.UTF_8));
         } catch (IOException e) {
             throw new RuntimeException(e);
         }
 
-        final FontConfig.Alias[] aliases = SystemFonts.buildSystemFallback(TEST_FONTS_XML,
-                TEST_FONT_DIR, TEST_UPDATABLE_FONT_DIR, oemCustomization, fallbackMap);
-        Typeface.initSystemDefaultTypefaces(fontMap, fallbackMap, aliases);
+        String oemXmlPath;
+        if (oemXml != null) {
+            try (FileOutputStream fos = new FileOutputStream(TEST_OEM_XML)) {
+                fos.write(oemXml.getBytes(StandardCharsets.UTF_8));
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+            oemXmlPath = TEST_OEM_XML;
+        } else {
+            oemXmlPath = null;
+        }
+
+        Map<String, File> updatableFontMap = new HashMap<>();
+        for (File file : new File(TEST_UPDATABLE_FONT_DIR).listFiles()) {
+            updatableFontMap.put(file.getName(), file);
+        }
+
+        FontConfig fontConfig;
+        try {
+            fontConfig = FontListParser.parse(
+                    TEST_FONTS_XML, TEST_FONT_DIR, oemXmlPath, TEST_OEM_DIR, updatableFontMap);
+        } catch (IOException | XmlPullParserException e) {
+            throw new RuntimeException(e);
+        }
+
+        Map<String, FontFamily[]> fallbackMap = SystemFonts.buildSystemFallback(fontConfig);
+        Map<String, Typeface> typefaceMap = SystemFonts.buildSystemTypefaces(
+                fontConfig, fallbackMap);
+
+        outFontMap.clear();
+        outFontMap.putAll(typefaceMap);
+        outFallbackMap.clear();
+        outFallbackMap.putAll(fallbackMap);
     }
 
     private static FontCustomizationParser.Result readFontCustomization(String oemXml) {
         try (InputStream is = new ByteArrayInputStream(oemXml.getBytes(StandardCharsets.UTF_8))) {
-            return FontCustomizationParser.parse(is, TEST_OEM_DIR);
+            return FontCustomizationParser.parse(is, TEST_OEM_DIR, null);
         } catch (IOException | XmlPullParserException e) {
             throw new RuntimeException(e);
         }
@@ -161,19 +196,22 @@
 
     @Test
     public void testBuildSystemFallback() {
-        final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
-        final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
-        final FontCustomizationParser.Result oemCustomization =
-                new FontCustomizationParser.Result();
+        FontConfig fontConfig;
+        try {
+            fontConfig = FontListParser.parse(
+                    SYSTEM_FONTS_XML, SYSTEM_FONT_DIR, null, TEST_OEM_DIR, null);
+        } catch (IOException | XmlPullParserException e) {
+            throw new RuntimeException(e);
+        }
+        assertFalse(fontConfig.getAliases().isEmpty());
+        assertFalse(fontConfig.getFontFamilies().isEmpty());
 
-        final FontConfig.Alias[] aliases = SystemFonts.buildSystemFallback(SYSTEM_FONTS_XML,
-                SYSTEM_FONT_DIR, oemCustomization, fallbackMap);
-
-        assertNotNull(aliases);
+        Map<String, FontFamily[]> fallbackMap = SystemFonts.buildSystemFallback(fontConfig);
         assertFalse(fallbackMap.isEmpty());
 
-        Typeface.initSystemDefaultTypefaces(fontMap, fallbackMap, aliases);
-        assertFalse(fontMap.isEmpty());
+        Map<String, Typeface> typefaceMap = SystemFonts.buildSystemTypefaces(
+                fontConfig, fallbackMap);
+        assertFalse(typefaceMap.isEmpty());
     }
 
     @Test
@@ -193,10 +231,8 @@
                 + "</familyset>";
         final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
         final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
-        final FontCustomizationParser.Result oemCustomization =
-                new FontCustomizationParser.Result();
 
-        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+        buildSystemFallback(xml, null, fontMap, fallbackMap);
 
         assertEquals(1, fontMap.size());
         assertTrue(fontMap.containsKey("sans-serif"));
@@ -223,10 +259,8 @@
                 + "</familyset>";
         final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
         final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
-        final FontCustomizationParser.Result oemCustomization =
-                new FontCustomizationParser.Result();
 
-        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+        buildSystemFallback(xml, null, fontMap, fallbackMap);
 
         final Paint paint = new Paint();
 
@@ -271,10 +305,8 @@
                 + "</familyset>";
         final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
         final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
-        final FontCustomizationParser.Result oemCustomization =
-                new FontCustomizationParser.Result();
 
-        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+        buildSystemFallback(xml, null, fontMap, fallbackMap);
 
         final Paint paint = new Paint();
 
@@ -318,10 +350,8 @@
                 + "</familyset>";
         final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
         final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
-        final FontCustomizationParser.Result oemCustomization =
-                new FontCustomizationParser.Result();
 
-        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+        buildSystemFallback(xml, null, fontMap, fallbackMap);
 
         final Paint paint = new Paint();
 
@@ -370,10 +400,8 @@
                 + "</familyset>";
         final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
         final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
-        final FontCustomizationParser.Result oemCustomization =
-                new FontCustomizationParser.Result();
 
-        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+        buildSystemFallback(xml, null, fontMap, fallbackMap);
 
         final Paint paint = new Paint();
 
@@ -418,10 +446,8 @@
                 + "</familyset>";
         final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
         final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
-        final FontCustomizationParser.Result oemCustomization =
-                new FontCustomizationParser.Result();
 
-        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+        buildSystemFallback(xml, null, fontMap, fallbackMap);
 
         final Paint paint = new Paint();
 
@@ -459,10 +485,8 @@
                 + "</familyset>";
         final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
         final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
-        final FontCustomizationParser.Result oemCustomization =
-                new FontCustomizationParser.Result();
 
-        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+        buildSystemFallback(xml, null, fontMap, fallbackMap);
 
         final Paint paint = new Paint();
 
@@ -500,10 +524,8 @@
                 + "</familyset>";
         final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
         final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
-        final FontCustomizationParser.Result oemCustomization =
-                new FontCustomizationParser.Result();
 
-        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+        buildSystemFallback(xml, null, fontMap, fallbackMap);
 
         final Paint paint = new Paint();
 
@@ -550,10 +572,8 @@
                 + "</familyset>";
         final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
         final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
-        final FontCustomizationParser.Result oemCustomization =
-                new FontCustomizationParser.Result();
 
-        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+        buildSystemFallback(xml, null, fontMap, fallbackMap);
 
         final Paint paint = new Paint();
         paint.setTypeface(fontMap.get("sans-serif"));
@@ -594,10 +614,8 @@
                 + "</familyset>";
         final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
         final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
-        final FontCustomizationParser.Result oemCustomization =
-                new FontCustomizationParser.Result();
 
-        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+        buildSystemFallback(xml, null, fontMap, fallbackMap);
 
         final Paint paint = new Paint();
 
@@ -635,10 +653,8 @@
                 + "</familyset>";
         final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
         final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
-        final FontCustomizationParser.Result oemCustomization =
-                new FontCustomizationParser.Result();
 
-        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+        buildSystemFallback(xml, null, fontMap, fallbackMap);
 
         final Paint paint = new Paint();
 
@@ -673,10 +689,8 @@
                 + "</fonts-modification>";
         final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
         final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
-        final FontCustomizationParser.Result oemCustomization =
-                readFontCustomization(oemXml);
 
-        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+        buildSystemFallback(xml, oemXml, fontMap, fallbackMap);
 
         final Paint paint = new Paint();
 
@@ -711,10 +725,8 @@
                 + "</fonts-modification>";
         final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
         final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
-        final FontCustomizationParser.Result oemCustomization =
-                readFontCustomization(oemXml);
 
-        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+        buildSystemFallback(xml, oemXml, fontMap, fallbackMap);
 
         final Paint paint = new Paint();
 
@@ -745,10 +757,8 @@
                 + "</fonts-modification>";
         final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
         final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
-        final FontCustomizationParser.Result oemCustomization =
-                readFontCustomization(oemXml);
 
-        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+        buildSystemFallback(xml, oemXml, fontMap, fallbackMap);
 
         final Paint paint = new Paint();
 
@@ -798,10 +808,8 @@
                 + "</fonts-modification>";
         final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
         final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
-        final FontCustomizationParser.Result oemCustomization =
-                readFontCustomization(oemXml);
 
-        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+        buildSystemFallback(xml, oemXml, fontMap, fallbackMap);
 
         final Paint paint = new Paint();
 
@@ -856,12 +864,10 @@
                 + "</familyset>";
         final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
         final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
-        final FontCustomizationParser.Result oemCustomization =
-                new FontCustomizationParser.Result();
 
         // Install all2em.ttf as a3em.ttf
         copyAssetToFile("fonts/all2em.ttf", new File(TEST_UPDATABLE_FONT_DIR, "a3em.ttf"));
-        buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+        buildSystemFallback(xml, null, fontMap, fallbackMap);
 
         final Paint paint = new Paint();
 
diff --git a/core/tests/coretests/src/android/graphics/TypefaceTest.java b/core/tests/coretests/src/android/graphics/TypefaceTest.java
index 392c6b7..d12f495 100644
--- a/core/tests/coretests/src/android/graphics/TypefaceTest.java
+++ b/core/tests/coretests/src/android/graphics/TypefaceTest.java
@@ -27,7 +27,6 @@
 import android.graphics.fonts.SystemFonts;
 import android.os.SharedMemory;
 import android.text.FontConfig;
-import android.util.Pair;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.LargeTest;
@@ -41,7 +40,6 @@
 import org.junit.runner.RunWith;
 
 import java.nio.ByteOrder;
-import java.util.HashMap;
 import java.util.Map;
 import java.util.Random;
 
@@ -197,10 +195,10 @@
     @SmallTest
     @Test
     public void testSerialize() throws Exception {
-        HashMap<String, Typeface> systemFontMap = new HashMap<>();
-        Pair<FontConfig.Alias[], Map<String, FontFamily[]>> res =
-                SystemFonts.initializePreinstalledFonts();
-        Typeface.initSystemDefaultTypefaces(systemFontMap, res.second, res.first);
+        FontConfig fontConfig = SystemFonts.getSystemPreinstalledFontConfig();
+        Map<String, FontFamily[]> fallbackMap = SystemFonts.buildSystemFallback(fontConfig);
+        Map<String, Typeface> systemFontMap = SystemFonts.buildSystemTypefaces(fontConfig,
+                fallbackMap);
         SharedMemory sharedMemory = Typeface.serializeFontMap(systemFontMap);
         Map<String, Typeface> copiedFontMap =
                 Typeface.deserializeFontMap(sharedMemory.mapReadOnly().order(ByteOrder.BIG_ENDIAN));
diff --git a/core/tests/coretests/src/android/os/VibrationEffectTest.java b/core/tests/coretests/src/android/os/VibrationEffectTest.java
index c357414..1d56e17 100644
--- a/core/tests/coretests/src/android/os/VibrationEffectTest.java
+++ b/core/tests/coretests/src/android/os/VibrationEffectTest.java
@@ -39,6 +39,7 @@
 
 import com.android.internal.R;
 
+import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.junit.MockitoJUnitRunner;
@@ -168,15 +169,30 @@
     }
 
     @Test
-    public void testScalePrebaked_ignoresScaleAndReturnsSameEffect() {
-        VibrationEffect initial = VibrationEffect.get(VibrationEffect.RINGTONES[1]);
-        assertSame(initial, initial.scale(0.5f));
+    public void testScalePrebaked_scalesFallbackEffect() {
+        VibrationEffect.Prebaked prebaked =
+                (VibrationEffect.Prebaked) VibrationEffect.get(VibrationEffect.RINGTONES[1]);
+        assertSame(prebaked, prebaked.scale(0.5f));
+
+        prebaked = new VibrationEffect.Prebaked(VibrationEffect.EFFECT_CLICK,
+                VibrationEffect.EFFECT_STRENGTH_MEDIUM, TEST_ONE_SHOT);
+        VibrationEffect.OneShot scaledFallback =
+                (VibrationEffect.OneShot) prebaked.scale(0.5f).getFallbackEffect();
+        assertEquals(34, scaledFallback.getAmplitude(), AMPLITUDE_SCALE_TOLERANCE);
     }
 
     @Test
-    public void testResolvePrebaked_ignoresDefaultAmplitudeAndReturnsSameEffect() {
-        VibrationEffect initial = VibrationEffect.get(VibrationEffect.RINGTONES[1]);
-        assertSame(initial, initial.resolve(1000));
+    public void testResolvePrebaked_resolvesFallbackEffectIfSet() {
+        VibrationEffect.Prebaked prebaked =
+                (VibrationEffect.Prebaked) VibrationEffect.get(VibrationEffect.RINGTONES[1]);
+        assertSame(prebaked, prebaked.resolve(1000));
+
+        prebaked = new VibrationEffect.Prebaked(VibrationEffect.EFFECT_CLICK,
+                VibrationEffect.EFFECT_STRENGTH_MEDIUM,
+                VibrationEffect.createOneShot(1, VibrationEffect.DEFAULT_AMPLITUDE));
+        VibrationEffect.OneShot resolvedFallback =
+                (VibrationEffect.OneShot) prebaked.resolve(10).getFallbackEffect();
+        assertEquals(10, resolvedFallback.getAmplitude());
     }
 
     @Test
@@ -352,6 +368,36 @@
                 INTENSITY_SCALE_TOLERANCE);
     }
 
+    @Test
+    public void getEffectStrength_returnsValueFromConstructor() {
+        VibrationEffect.Prebaked effect = new VibrationEffect.Prebaked(VibrationEffect.EFFECT_CLICK,
+                VibrationEffect.EFFECT_STRENGTH_LIGHT, null);
+        Assert.assertEquals(VibrationEffect.EFFECT_STRENGTH_LIGHT, effect.getEffectStrength());
+    }
+
+    @Test
+    public void getFallbackEffect_withFallbackDisabled_isNull() {
+        VibrationEffect fallback = VibrationEffect.createOneShot(100, 100);
+        VibrationEffect.Prebaked effect = new VibrationEffect.Prebaked(VibrationEffect.EFFECT_CLICK,
+                false, VibrationEffect.EFFECT_STRENGTH_LIGHT);
+        Assert.assertNull(effect.getFallbackEffect());
+    }
+
+    @Test
+    public void getFallbackEffect_withoutEffectSet_isNull() {
+        VibrationEffect.Prebaked effect = new VibrationEffect.Prebaked(VibrationEffect.EFFECT_CLICK,
+                true, VibrationEffect.EFFECT_STRENGTH_LIGHT);
+        Assert.assertNull(effect.getFallbackEffect());
+    }
+
+    @Test
+    public void getFallbackEffect_withFallback_returnsValueFromConstructor() {
+        VibrationEffect fallback = VibrationEffect.createOneShot(100, 100);
+        VibrationEffect.Prebaked effect = new VibrationEffect.Prebaked(VibrationEffect.EFFECT_CLICK,
+                VibrationEffect.EFFECT_STRENGTH_LIGHT, fallback);
+        Assert.assertEquals(fallback, effect.getFallbackEffect());
+    }
+
     private Resources mockRingtoneResources() {
         return mockRingtoneResources(new String[] {
                 RINGTONE_URI_1,
diff --git a/core/tests/coretests/src/android/text/FontFallbackSetup.java b/core/tests/coretests/src/android/text/FontFallbackSetup.java
index 64e6f82..e301037 100644
--- a/core/tests/coretests/src/android/text/FontFallbackSetup.java
+++ b/core/tests/coretests/src/android/text/FontFallbackSetup.java
@@ -19,14 +19,15 @@
 import android.annotation.NonNull;
 import android.content.Context;
 import android.content.res.AssetManager;
+import android.graphics.FontListParser;
 import android.graphics.Typeface;
-import android.graphics.fonts.FontCustomizationParser;
 import android.graphics.fonts.FontFamily;
 import android.graphics.fonts.SystemFonts;
-import android.util.ArrayMap;
 
 import androidx.test.InstrumentationRegistry;
 
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -34,12 +35,13 @@
 import java.nio.charset.Charset;
 import java.nio.file.Files;
 import java.nio.file.StandardCopyOption;
+import java.util.Map;
 
 public class FontFallbackSetup implements AutoCloseable {
     private final String[] mTestFontFiles;
     private final String mXml;
     private final String mTestFontsDir;
-    final ArrayMap<String, Typeface> mFontMap = new ArrayMap<>();
+    private final Map<String, Typeface> mFontMap;
 
     public FontFallbackSetup(@NonNull String testSubDir, @NonNull String[] testFontFiles,
             @NonNull String xml) {
@@ -75,12 +77,15 @@
             throw new RuntimeException(e);
         }
 
-        final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
-        final FontCustomizationParser.Result oemCustomization =
-                new FontCustomizationParser.Result();
-        final FontConfig.Alias[] aliases = SystemFonts.buildSystemFallback(testFontsXml,
-                mTestFontsDir, oemCustomization, fallbackMap);
-        Typeface.initSystemDefaultTypefaces(mFontMap, fallbackMap, aliases);
+        FontConfig fontConfig;
+        try {
+            fontConfig = FontListParser.parse(testFontsXml, mTestFontsDir, null, null, null);
+        } catch (IOException | XmlPullParserException e) {
+            throw new RuntimeException(e);
+        }
+
+        Map<String, FontFamily[]> fallbackMap = SystemFonts.buildSystemFallback(fontConfig);
+        mFontMap = SystemFonts.buildSystemTypefaces(fontConfig, fallbackMap);
     }
 
     @NonNull
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index af13cc0..2770ed8 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -45,6 +45,7 @@
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -681,6 +682,19 @@
     }
 
     @Test
+    public void testNotifyCaptionInsetsOnlyChange() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            final InsetsState state = new InsetsState(mController.getState(), true);
+            reset(mTestHost);
+            mController.setCaptionInsetsHeight(100);
+            verify(mTestHost).notifyInsetsChanged();
+            reset(mTestHost);
+            mController.setCaptionInsetsHeight(0);
+            verify(mTestHost).notifyInsetsChanged();
+        });
+    }
+
+    @Test
     public void testRequestedState() {
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
             final InsetsState state = mTestHost.getRequestedState();
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index f371a7f..c67174f 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -23,7 +23,7 @@
 import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
 import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE;
 import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS;
-import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE;
+import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -35,6 +35,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import android.content.Context;
 import android.os.Binder;
@@ -50,6 +51,9 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 /**
  * Tests for {@link ViewRootImpl}
  *
@@ -180,7 +184,7 @@
     public void adjustLayoutParamsForCompatibility_noAdjustBehavior() {
         final WindowInsetsController controller = mViewRootImpl.getInsetsController();
         final WindowManager.LayoutParams attrs = mViewRootImpl.mWindowAttributes;
-        final int behavior = BEHAVIOR_SHOW_BARS_BY_SWIPE;
+        final int behavior = BEHAVIOR_DEFAULT;
         controller.setSystemBarsBehavior(behavior);
         attrs.systemUiVisibility = SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
         ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
@@ -196,6 +200,26 @@
     }
 
     /**
+     * Ensure scroll capture request handles a ViewRootImpl with no view tree.
+     */
+    @Test
+    public void requestScrollCapture_withoutContentRoot() {
+        final CountDownLatch latch = new CountDownLatch(1);
+        mViewRootImpl.handleScrollCaptureRequest(new IScrollCaptureCallbacks.Default() {
+            @Override
+            public void onUnavailable() {
+                latch.countDown();
+            }
+        });
+        try {
+            if (latch.await(100, TimeUnit.MILLISECONDS)) {
+                return; // pass
+            }
+        } catch (InterruptedException e) { /* ignore */ }
+        fail("requestScrollCapture did not respond");
+    }
+
+    /**
      * When window doesn't have focus, keys should be dropped.
      */
     @Test
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java b/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java
index 82788c8..5def552 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java
@@ -16,14 +16,24 @@
 
 package android.view.textclassifier;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 
+import android.app.PendingIntent;
+import android.app.RemoteAction;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.drawable.Icon;
 import android.os.Bundle;
 import android.os.LocaleList;
 import android.os.Parcel;
 
+import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
@@ -107,4 +117,46 @@
         assertEquals(1, resultSystemTcMetadata.getUserId());
         assertFalse(resultSystemTcMetadata.useDefaultTextClassifier());
     }
+
+    @Test
+    public void testToBuilder() {
+        final Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        final int startIndex = 13;
+        final int endIndex = 37;
+        final String id = "id";
+        final Icon icon1 = generateTestIcon(5, 5, Color.RED);
+
+        final TextClassification classification = new TextClassification.Builder()
+                .addAction(new RemoteAction(icon1, "title1", "desc1",
+                        PendingIntent.getActivity(context, 0, new Intent("action1"), 0)))
+                .setEntityType(TextClassifier.TYPE_ADDRESS, 1.0f)
+                .build();
+        final TextSelection textSelection = new TextSelection.Builder(startIndex, endIndex)
+                .setId(id)
+                .setEntityType(TextClassifier.TYPE_ADDRESS, 1.0f)
+                .setExtras(BUNDLE)
+                .setTextClassification(classification)
+                .build();
+
+        final TextSelection fromBuilder = textSelection.toBuilder().build();
+
+        assertThat(fromBuilder.getId()).isEqualTo(textSelection.getId());
+        assertThat(fromBuilder.getSelectionStartIndex())
+                .isEqualTo(textSelection.getSelectionStartIndex());
+        assertThat(fromBuilder.getSelectionEndIndex())
+                .isEqualTo(textSelection.getSelectionEndIndex());
+        assertThat(fromBuilder.getTextClassification())
+                .isSameInstanceAs(textSelection.getTextClassification());
+        assertThat(fromBuilder.getExtras()).isSameInstanceAs(textSelection.getExtras());
+    }
+
+    private Icon generateTestIcon(int width, int height, int colorValue) {
+        final int numPixels = width * height;
+        final int[] colors = new int[numPixels];
+        for (int i = 0; i < numPixels; ++i) {
+            colors[i] = colorValue;
+        }
+        final Bitmap bitmap = Bitmap.createBitmap(colors, width, height, Bitmap.Config.ARGB_8888);
+        return Icon.createWithBitmap(bitmap);
+    }
 }
diff --git a/core/tests/coretests/src/android/widget/AbsSeekBarTest.java b/core/tests/coretests/src/android/widget/AbsSeekBarTest.java
index 5371a0f..ccd873d 100644
--- a/core/tests/coretests/src/android/widget/AbsSeekBarTest.java
+++ b/core/tests/coretests/src/android/widget/AbsSeekBarTest.java
@@ -30,7 +30,6 @@
 import android.graphics.drawable.ShapeDrawable;
 import android.graphics.drawable.shapes.RectShape;
 import android.platform.test.annotations.Presubmit;
-import android.view.View;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
@@ -48,6 +47,7 @@
 @Presubmit
 public class AbsSeekBarTest {
 
+    public static final int PADDING = 10;
     private Context mContext;
     private AbsSeekBar mBar;
 
@@ -59,34 +59,42 @@
 
     @Test
     public void testExclusionForThumb_limitedTo48dp() {
-        mBar.setPadding(10, 10, 10, 10);
+        mBar.setPadding(PADDING, PADDING, PADDING, PADDING);
         mBar.setThumb(newThumb(dpToPxSize(20)));
         mBar.setMin(0);
         mBar.setMax(100);
         mBar.setProgress(50);
+
+        final int thumbOffset = mBar.getThumbOffset();
+
         measureAndLayout(dpToPxSize(200), dpToPxSize(100));
         List<Rect> exclusions = mBar.getSystemGestureExclusionRects();
 
         assertEquals("exclusions should be size 1, but was " + exclusions, 1, exclusions.size());
         assertEquals("exclusion should be centered on thumb",
-                center(mBar), center(exclusions.get(0)));
+                center(offset(mBar.getThumb().getBounds(), PADDING - thumbOffset, PADDING)),
+                center(exclusions.get(0)));
         assertEquals("exclusion should be 48dp high", dpToPxSize(48), exclusions.get(0).height());
         assertEquals("exclusion should be 48dp wide", dpToPxSize(48), exclusions.get(0).width());
     }
 
     @Test
     public void testExclusionForThumb_limitedToHeight() {
-        mBar.setPadding(10, 10, 10, 10);
+        mBar.setPadding(PADDING, PADDING, PADDING, PADDING);
         mBar.setThumb(newThumb(dpToPxSize(20)));
         mBar.setMin(0);
         mBar.setMax(100);
         mBar.setProgress(50);
+
+        final int thumbOffset = mBar.getThumbOffset();
+
         measureAndLayout(dpToPxSize(200), dpToPxSize(32));
         List<Rect> exclusions = mBar.getSystemGestureExclusionRects();
 
         assertEquals("exclusions should be size 1, but was " + exclusions, 1, exclusions.size());
         assertEquals("exclusion should be centered on thumb",
-                center(mBar), center(exclusions.get(0)));
+                center(offset(mBar.getThumb().getBounds(), PADDING - thumbOffset, PADDING)),
+                center(exclusions.get(0)));
         assertEquals("exclusion should be 32dp high", dpToPxSize(32), exclusions.get(0).height());
         assertEquals("exclusion should be 32dp wide", dpToPxSize(32), exclusions.get(0).width());
     }
@@ -95,7 +103,7 @@
     public void testExclusionForThumb_passesThroughUserExclusions() {
         mBar.setSystemGestureExclusionRects(Arrays.asList(new Rect(1, 2, 3, 4)));
 
-        mBar.setPadding(10, 10, 10, 10);
+        mBar.setPadding(PADDING, PADDING, PADDING, PADDING);
         mBar.setThumb(newThumb(dpToPxSize(20)));
         mBar.setMin(0);
         mBar.setMax(100);
@@ -110,12 +118,37 @@
         assertThat(mBar.getSystemGestureExclusionRects(), hasSize(2));
     }
 
+    @Test
+    public void testGrowRectTo_evenInitialDifference() {
+        doGrowRectTest(new Rect(0, 0, 0, 0), 10, new Rect(-5, -5, 5, 5));
+    }
+
+    @Test
+    public void testGrowRectTo_unevenInitialDifference() {
+        doGrowRectTest(new Rect(0, 0, 1, 1), 10, new Rect(-5, -5, 5, 5));
+    }
+
+    @Test
+    public void testGrowRectTo_unevenInitialDifference_unevenSize() {
+        doGrowRectTest(new Rect(0, 0, 0, 0), 9, new Rect(-5, -5, 4, 4));
+    }
+
+    public void doGrowRectTest(Rect in, int minimumSize, Rect expected) {
+        Rect result = new Rect(in);
+        mBar.growRectTo(result, minimumSize);
+
+        assertEquals("grown rect", expected, result);
+        assertEquals("grown rect center point", center(expected), center(result));
+    }
+
     private Point center(Rect rect) {
         return new Point(rect.centerX(), rect.centerY());
     }
 
-    private Point center(View view) {
-        return center(new Rect(view.getLeft(), view.getTop(), view.getRight(), view.getBottom()));
+    private Rect offset(Rect rect, int dx, int dy) {
+        Rect result = new Rect(rect);
+        result.offset(dx, dy);
+        return result;
     }
 
     private ShapeDrawable newThumb(int size) {
diff --git a/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java b/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java
index 2ede751..c9c81ac 100644
--- a/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java
@@ -34,6 +34,8 @@
 
 import org.junit.Test;
 
+import java.util.Arrays;
+
 /**
  * Test class for {@link MeasuredEnergyStats}.
  *
@@ -114,7 +116,7 @@
     }
 
     @Test
-    public void testReadWriteSummaryParcel() {
+    public void testCreateAndReadSummaryFromParcel() {
         final boolean[] supportedEnergyBuckets = new boolean[NUMBER_ENERGY_BUCKETS];
         supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
         supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false;
@@ -126,35 +128,21 @@
         stats.updateBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
 
         final Parcel parcel = Parcel.obtain();
-        MeasuredEnergyStats.writeSummaryToParcel(stats, parcel);
-
-
-        final boolean[] newSupportedEnergyBuckets = new boolean[NUMBER_ENERGY_BUCKETS];
-        newSupportedEnergyBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
-        newSupportedEnergyBuckets[ENERGY_BUCKET_SCREEN_DOZE] = true; // switched from false to true
-        newSupportedEnergyBuckets[ENERGY_BUCKET_SCREEN_OTHER] = false; // switched true to false
-        MeasuredEnergyStats newStats = new MeasuredEnergyStats(newSupportedEnergyBuckets);
+        MeasuredEnergyStats.writeSummaryToParcel(stats, parcel, false);
         parcel.setDataPosition(0);
-        MeasuredEnergyStats.readSummaryFromParcel(newStats, parcel);
+        MeasuredEnergyStats newStats = MeasuredEnergyStats.createAndReadSummaryFromParcel(parcel);
 
         for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
-            if (!newSupportedEnergyBuckets[i]) {
-                assertFalse(newStats.isEnergyBucketSupported(i));
-                assertEquals(ENERGY_DATA_UNAVAILABLE, newStats.getAccumulatedBucketEnergy(i));
-            } else if (!supportedEnergyBuckets[i]) {
-                assertTrue(newStats.isEnergyBucketSupported(i));
-                assertEquals(0L, newStats.getAccumulatedBucketEnergy(i));
-            } else {
-                assertTrue(newStats.isEnergyBucketSupported(i));
-                assertEquals(stats.getAccumulatedBucketEnergy(i),
-                        newStats.getAccumulatedBucketEnergy(i));
-            }
+            assertEquals(stats.isEnergyBucketSupported(i),
+                    newStats.isEnergyBucketSupported(i));
+            assertEquals(stats.getAccumulatedBucketEnergy(i),
+                    newStats.getAccumulatedBucketEnergy(i));
         }
         parcel.recycle();
     }
 
     @Test
-    public void testCreateAndReadSummaryFromParcel() {
+    public void testCreateAndReadSummaryFromParcel_existingTemplate() {
         final boolean[] supportedEnergyBuckets = new boolean[NUMBER_ENERGY_BUCKETS];
         supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
         supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false;
@@ -171,7 +159,7 @@
         stats.updateBucket(ENERGY_BUCKET_SCREEN_OTHER, 63, true);
 
         final Parcel parcel = Parcel.obtain();
-        MeasuredEnergyStats.writeSummaryToParcel(stats, parcel);
+        MeasuredEnergyStats.writeSummaryToParcel(stats, parcel, false);
 
         final boolean[] newSupportedEnergyBuckets = new boolean[NUMBER_ENERGY_BUCKETS];
         newSupportedEnergyBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
@@ -200,6 +188,55 @@
     }
 
     @Test
+    public void testCreateAndReadSummaryFromParcel_skipZero() {
+        final boolean[] supportedEnergyBuckets = new boolean[NUMBER_ENERGY_BUCKETS];
+        Arrays.fill(supportedEnergyBuckets, true);
+
+        final MeasuredEnergyStats stats = new MeasuredEnergyStats(supportedEnergyBuckets);
+        // Accumulate energy in one bucket, the rest should be zero
+        stats.updateBucket(ENERGY_BUCKET_SCREEN_ON, 200, true);
+
+        final Parcel includeZerosParcel = Parcel.obtain();
+        MeasuredEnergyStats.writeSummaryToParcel(stats, includeZerosParcel, false);
+        includeZerosParcel.setDataPosition(0);
+
+        MeasuredEnergyStats newStats = MeasuredEnergyStats.createAndReadSummaryFromParcel(
+                includeZerosParcel);
+
+        for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
+            if (i == ENERGY_BUCKET_SCREEN_ON) {
+                assertEquals(stats.isEnergyBucketSupported(i),
+                        newStats.isEnergyBucketSupported(i));
+                assertEquals(stats.getAccumulatedBucketEnergy(i),
+                        newStats.getAccumulatedBucketEnergy(i));
+            } else {
+                assertTrue(newStats.isEnergyBucketSupported(i));
+                assertEquals(0L, newStats.getAccumulatedBucketEnergy(i));
+            }
+        }
+        includeZerosParcel.recycle();
+
+        final Parcel skipZerosParcel = Parcel.obtain();
+        MeasuredEnergyStats.writeSummaryToParcel(stats, skipZerosParcel, true);
+        skipZerosParcel.setDataPosition(0);
+
+        newStats = MeasuredEnergyStats.createAndReadSummaryFromParcel(skipZerosParcel);
+
+        for (int i = 0; i < NUMBER_ENERGY_BUCKETS; i++) {
+            if (i == ENERGY_BUCKET_SCREEN_ON) {
+                assertEquals(stats.isEnergyBucketSupported(i),
+                        newStats.isEnergyBucketSupported(i));
+                assertEquals(stats.getAccumulatedBucketEnergy(i),
+                        newStats.getAccumulatedBucketEnergy(i));
+            } else {
+                assertFalse(newStats.isEnergyBucketSupported(i));
+                assertEquals(ENERGY_DATA_UNAVAILABLE, newStats.getAccumulatedBucketEnergy(i));
+            }
+        }
+        skipZerosParcel.recycle();
+    }
+
+    @Test
     public void testUpdateBucket() {
         final boolean[] supportedEnergyBuckets = new boolean[NUMBER_ENERGY_BUCKETS];
         supportedEnergyBuckets[ENERGY_BUCKET_SCREEN_ON] = true;
diff --git a/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java b/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java
index 7eca320..272f228 100644
--- a/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java
+++ b/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.statusbar;
 
+import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import android.os.Binder;
@@ -56,8 +58,8 @@
                 0x20 /* disabledFlags2 */,
                 new Binder() /* imeToken */,
                 true /* navbarColorManagedByIme */,
+                BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE,
                 true /* appFullscreen */,
-                true /* appImmersive */,
                 new int[0] /* transientBarTypes */);
 
         final RegisterStatusBarResult copy = clone(original);
@@ -76,8 +78,8 @@
         assertThat(copy.mDisabledFlags2).isEqualTo(original.mDisabledFlags2);
         assertThat(copy.mImeToken).isSameInstanceAs(original.mImeToken);
         assertThat(copy.mNavbarColorManagedByIme).isEqualTo(original.mNavbarColorManagedByIme);
+        assertThat(copy.mBehavior).isEqualTo(original.mBehavior);
         assertThat(copy.mAppFullscreen).isEqualTo(original.mAppFullscreen);
-        assertThat(copy.mAppImmersive).isEqualTo(original.mAppImmersive);
         assertThat(copy.mTransientBarTypes).isEqualTo(original.mTransientBarTypes);
     }
 
diff --git a/core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java b/core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java
index 4c3eaeb..7175f56 100644
--- a/core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java
@@ -15,6 +15,8 @@
  */
 package com.android.internal.util;
 
+import static android.Manifest.permission.NETWORK_SETTINGS;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
@@ -82,6 +84,7 @@
     private int mAllowCoarseLocationApps;
     private int mFineLocationPermission;
     private int mAllowFineLocationApps;
+    private int mNetworkSettingsPermission;
     private int mCurrentUser;
     private boolean mIsLocationEnabled;
     private boolean mThrowSecurityException;
@@ -138,6 +141,7 @@
         mFineLocationPermission = PackageManager.PERMISSION_DENIED;
         mAllowCoarseLocationApps = AppOpsManager.MODE_ERRORED;
         mAllowFineLocationApps = AppOpsManager.MODE_ERRORED;
+        mNetworkSettingsPermission = PackageManager.PERMISSION_DENIED;
     }
 
     private void setupMockInterface() {
@@ -151,6 +155,8 @@
                 .thenReturn(mCoarseLocationPermission);
         when(mMockContext.checkPermission(mManifestStringFine, -1, mUid))
                 .thenReturn(mFineLocationPermission);
+        when(mMockContext.checkPermission(NETWORK_SETTINGS, -1, mUid))
+                .thenReturn(mNetworkSettingsPermission);
         when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(mIsLocationEnabled);
     }
 
@@ -264,6 +270,21 @@
         assertEquals(LocationPermissionChecker.ERROR_LOCATION_MODE_OFF, result);
     }
 
+    @Test
+    public void testenforceCanAccessScanResults_LocationModeDisabledHasNetworkSettings()
+            throws Exception {
+        mThrowSecurityException = false;
+        mIsLocationEnabled = false;
+        mNetworkSettingsPermission = PackageManager.PERMISSION_GRANTED;
+        setupTestCase();
+
+        final int result =
+                mChecker.checkLocationPermissionWithDetailInfo(
+                        TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null);
+        assertEquals(LocationPermissionChecker.SUCCEEDED, result);
+    }
+
+
     private static void assertThrows(Class<? extends Exception> exceptionClass, Runnable r) {
         try {
             r.run();
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index fb8b17c..201f649 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -102,6 +102,14 @@
 }
 
 prebuilt_etc {
+    name: "privapp_whitelist_com.android.imsserviceentitlement",
+    product_specific: true,
+    sub_dir: "permissions",
+    src: "com.android.imsserviceentitlement.xml",
+    filename_from_src: true,
+}
+
+prebuilt_etc {
     name: "privapp_whitelist_com.android.launcher3",
     system_ext_specific: true,
     sub_dir: "permissions",
diff --git a/data/etc/car/com.android.car.shell.xml b/data/etc/car/com.android.car.shell.xml
index 32666c8..6132d53 100644
--- a/data/etc/car/com.android.car.shell.xml
+++ b/data/etc/car/com.android.car.shell.xml
@@ -15,7 +15,9 @@
   ~ limitations under the License
   -->
 <permissions>
-    <privapp-permissions package="com.android.car.shell">
+    <!-- CarShell now overrides the shell package and adding permission here
+         is ok. -->
+    <privapp-permissions package="com.android.shell">
         <permission name="android.permission.INSTALL_PACKAGES" />
         <permission name="android.permission.MEDIA_CONTENT_CONTROL"/>
     </privapp-permissions>
diff --git a/data/etc/com.android.imsserviceentitlement.xml b/data/etc/com.android.imsserviceentitlement.xml
new file mode 100644
index 0000000..4fd91c3
--- /dev/null
+++ b/data/etc/com.android.imsserviceentitlement.xml
@@ -0,0 +1,22 @@
+<?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.imsserviceentitlement">
+        <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+        <permission name="android.permission.MODIFY_PHONE_STATE"/>
+    </privapp-permissions>
+</permissions>
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
index 73fff72..ff38117 100644
--- a/graphics/java/android/graphics/FontListParser.java
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -16,10 +16,14 @@
 
 package android.graphics;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
+import android.graphics.fonts.FontCustomizationParser;
+import android.graphics.fonts.FontStyle;
 import android.graphics.fonts.FontVariationAxis;
 import android.os.Build;
+import android.os.LocaleList;
 import android.text.FontConfig;
 import android.util.Xml;
 
@@ -27,15 +31,16 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import java.util.regex.Pattern;
 
 /**
  * Parser for font config files.
- *
  * @hide
  */
 public class FontListParser {
@@ -43,59 +48,102 @@
     /* Parse fallback list (no names) */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public static FontConfig parse(InputStream in) throws XmlPullParserException, IOException {
-        return parse(in, "/system/fonts", null);
+        XmlPullParser parser = Xml.newPullParser();
+        parser.setInput(in, null);
+        parser.nextTag();
+        return readFamilies(parser, "/system/fonts/", new FontCustomizationParser.Result(), null);
     }
 
     /**
-     * Parse the fonts.xml
+     * Parses system font config XMLs
+     *
+     * @param fontsXmlPath location of fonts.xml
+     * @param systemFontDir location of system font directory
+     * @param oemCustomizationXmlPath location of oem_customization.xml
+     * @param productFontDir location of oem customized font directory
+     * @param updatableFontMap map of updated font files.
+     * @return font configuration
+     * @throws IOException
+     * @throws XmlPullParserException
      */
-    public static FontConfig parse(InputStream in, String fontDir,
-            @Nullable String updatableFontDir) throws XmlPullParserException, IOException {
-        try {
+    public static FontConfig parse(
+            @NonNull String fontsXmlPath,
+            @NonNull String systemFontDir,
+            @Nullable String oemCustomizationXmlPath,
+            @Nullable String productFontDir,
+            @Nullable Map<String, File> updatableFontMap
+    ) throws IOException, XmlPullParserException {
+        FontCustomizationParser.Result oemCustomization;
+        if (oemCustomizationXmlPath != null) {
+            try (InputStream is = new FileInputStream(oemCustomizationXmlPath)) {
+                oemCustomization = FontCustomizationParser.parse(is, productFontDir,
+                        updatableFontMap);
+            } catch (IOException e) {
+                // OEM customization may not exists. Ignoring
+                oemCustomization = new FontCustomizationParser.Result();
+            }
+        } else {
+            oemCustomization = new FontCustomizationParser.Result();
+        }
+
+        try (InputStream is = new FileInputStream(fontsXmlPath)) {
             XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(in, null);
+            parser.setInput(is, null);
             parser.nextTag();
-            return readFamilies(parser, fontDir, updatableFontDir);
-        } finally {
-            in.close();
+            return readFamilies(parser, systemFontDir, oemCustomization, updatableFontMap);
         }
     }
 
-    private static FontConfig readFamilies(XmlPullParser parser, String fontDir,
-            @Nullable String updatableFontDir) throws XmlPullParserException, IOException {
+    private static FontConfig readFamilies(
+            @NonNull XmlPullParser parser,
+            @NonNull String fontDir,
+            @NonNull FontCustomizationParser.Result customization,
+            @Nullable Map<String, File> updatableFontMap)
+            throws XmlPullParserException, IOException {
         List<FontConfig.Family> families = new ArrayList<>();
-        List<FontConfig.Alias> aliases = new ArrayList<>();
+        List<FontConfig.Alias> aliases = new ArrayList<>(customization.getAdditionalAliases());
+
+        Map<String, FontConfig.Family> oemNamedFamilies =
+                customization.getAdditionalNamedFamilies();
 
         parser.require(XmlPullParser.START_TAG, null, "familyset");
         while (parser.next() != XmlPullParser.END_TAG) {
             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
             String tag = parser.getName();
             if (tag.equals("family")) {
-                families.add(readFamily(parser, fontDir, updatableFontDir));
+                FontConfig.Family family = readFamily(parser, fontDir, updatableFontMap);
+                String name = family.getFallbackName();
+                if (name == null || !oemNamedFamilies.containsKey(name)) {
+                    // The OEM customization overrides system named family. Skip if OEM
+                    // customization XML defines the same named family.
+                    families.add(family);
+                }
             } else if (tag.equals("alias")) {
                 aliases.add(readAlias(parser));
             } else {
                 skip(parser);
             }
         }
-        return new FontConfig(families.toArray(new FontConfig.Family[families.size()]),
-                aliases.toArray(new FontConfig.Alias[aliases.size()]));
+
+        families.addAll(oemNamedFamilies.values());
+        return new FontConfig(families, aliases);
     }
 
     /**
-     * Reads a family element
+     * Read family tag in fonts.xml or oem_customization.xml
      */
     public static FontConfig.Family readFamily(XmlPullParser parser, String fontDir,
-            @Nullable String updatableFontDir) throws XmlPullParserException, IOException {
+            @Nullable Map<String, File> updatableFontMap)
+            throws XmlPullParserException, IOException {
         final String name = parser.getAttributeValue(null, "name");
         final String lang = parser.getAttributeValue("", "lang");
         final String variant = parser.getAttributeValue(null, "variant");
-        final List<FontConfig.Font> fonts = new ArrayList<FontConfig.Font>();
+        final List<FontConfig.Font> fonts = new ArrayList<>();
         while (parser.next() != XmlPullParser.END_TAG) {
             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
             final String tag = parser.getName();
             if (tag.equals("font")) {
-                fonts.add(readFont(parser, fontDir, updatableFontDir));
+                fonts.add(readFont(parser, fontDir, updatableFontMap));
             } else {
                 skip(parser);
             }
@@ -108,19 +156,22 @@
                 intVariant = FontConfig.Family.VARIANT_ELEGANT;
             }
         }
-        return new FontConfig.Family(name, fonts.toArray(new FontConfig.Font[fonts.size()]), lang,
-                intVariant);
+        return new FontConfig.Family(fonts, name, LocaleList.forLanguageTags(lang), intVariant);
     }
 
     /** Matches leading and trailing XML whitespace. */
     private static final Pattern FILENAME_WHITESPACE_PATTERN =
             Pattern.compile("^[ \\n\\r\\t]+|[ \\n\\r\\t]+$");
 
-    private static FontConfig.Font readFont(XmlPullParser parser, String fontDir,
-            @Nullable String updatableFontDir) throws XmlPullParserException, IOException {
+    private static FontConfig.Font readFont(
+            @NonNull XmlPullParser parser,
+            @NonNull String fontDir,
+            @Nullable Map<String, File> updatableFontMap)
+            throws XmlPullParserException, IOException {
+
         String indexStr = parser.getAttributeValue(null, "index");
         int index = indexStr == null ? 0 : Integer.parseInt(indexStr);
-        List<FontVariationAxis> axes = new ArrayList<FontVariationAxis>();
+        List<FontVariationAxis> axes = new ArrayList<>();
         String weightStr = parser.getAttributeValue(null, "weight");
         int weight = weightStr == null ? 400 : Integer.parseInt(weightStr);
         boolean isItalic = "italic".equals(parser.getAttributeValue(null, "style"));
@@ -139,20 +190,45 @@
             }
         }
         String sanitizedName = FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll("");
-        String fontName = findFontFile(sanitizedName, fontDir, updatableFontDir);
-        return new FontConfig.Font(fontName, index, axes.toArray(
-                new FontVariationAxis[axes.size()]), weight, isItalic, fallbackFor);
+        String updatedName = findUpdatedFontFile(sanitizedName, updatableFontMap);
+        String filePath;
+        String originalPath;
+        if (updatedName != null) {
+            filePath = updatedName;
+            originalPath = fontDir + sanitizedName;
+        } else {
+            filePath = fontDir + sanitizedName;
+            originalPath = null;
+        }
+
+        String varSettings;
+        if (axes.isEmpty()) {
+            varSettings = "";
+        } else {
+            varSettings = FontVariationAxis.toFontVariationSettings(
+                    axes.toArray(new FontVariationAxis[0]));
+        }
+
+        return new FontConfig.Font(new File(filePath),
+                originalPath == null ? null : new File(originalPath),
+                new FontStyle(
+                        weight,
+                        isItalic ? FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT
+                ),
+                index,
+                varSettings,
+                fallbackFor);
     }
 
-    private static String findFontFile(String fileName, String fontDir,
-            @Nullable String updatableFontDir) {
-        if (updatableFontDir != null) {
-            String updatableFontName = updatableFontDir + fileName;
-            if (new File(updatableFontName).exists()) {
-                return updatableFontName;
+    private static String findUpdatedFontFile(String name,
+            @Nullable Map<String, File> updatableFontMap) {
+        if (updatableFontMap != null) {
+            File updatedFile = updatableFontMap.get(name);
+            if (updatedFile != null) {
+                return updatedFile.getAbsolutePath();
             }
         }
-        return fontDir + fileName;
+        return null;
     }
 
     private static FontVariationAxis readAxis(XmlPullParser parser)
@@ -188,12 +264,12 @@
         int depth = 1;
         while (depth > 0) {
             switch (parser.next()) {
-            case XmlPullParser.START_TAG:
-                depth++;
-                break;
-            case XmlPullParser.END_TAG:
-                depth--;
-                break;
+                case XmlPullParser.START_TAG:
+                    depth++;
+                    break;
+                case XmlPullParser.END_TAG:
+                    depth--;
+                    break;
             }
         }
     }
diff --git a/graphics/java/android/graphics/Point.java b/graphics/java/android/graphics/Point.java
index 61a4749..cf2f970 100644
--- a/graphics/java/android/graphics/Point.java
+++ b/graphics/java/android/graphics/Point.java
@@ -20,8 +20,6 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import java.io.PrintWriter;
-
 /**
  * Point holds two integer coordinates
  */
@@ -72,17 +70,6 @@
         return this.x == x && this.y == y;
     }
 
-    /**
-     * Dumps a human-readable shortened string of the point into the given
-     * stream
-     *
-     * @param pw The {@link PrintWriter} into which the string representation of
-     *           the point will be written.
-     */
-    public final void dump(@NonNull PrintWriter pw) {
-        pw.print("["); pw.print(x); pw.print(","); pw.print(y); pw.print("]");
-    }
-
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
diff --git a/graphics/java/android/graphics/RecordingCanvas.java b/graphics/java/android/graphics/RecordingCanvas.java
index 2d626b9..8dd7f31 100644
--- a/graphics/java/android/graphics/RecordingCanvas.java
+++ b/graphics/java/android/graphics/RecordingCanvas.java
@@ -220,7 +220,7 @@
             CanvasProperty<Float> progress, RuntimeShader shader) {
         nDrawRipple(mNativeCanvasWrapper, cx.getNativeContainer(), cy.getNativeContainer(),
                 radius.getNativeContainer(), paint.getNativeContainer(),
-                progress.getNativeContainer(), shader.getNativeShaderFactory());
+                progress.getNativeContainer(), shader.getNativeShaderBuilder());
     }
 
     /**
diff --git a/graphics/java/android/graphics/RuntimeShader.java b/graphics/java/android/graphics/RuntimeShader.java
index 7f2e503..1ace322 100644
--- a/graphics/java/android/graphics/RuntimeShader.java
+++ b/graphics/java/android/graphics/RuntimeShader.java
@@ -17,7 +17,6 @@
 package android.graphics;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 
 import libcore.util.NativeAllocationRegistry;
 
@@ -33,14 +32,12 @@
                 RuntimeShader.class.getClassLoader(), nativeGetFinalizer());
     }
 
-    private byte[] mUniforms;
-    private Shader[] mInputShaders;
     private boolean mIsOpaque;
 
     /**
-     * Current native shader factory instance.
+     * Current native shader builder instance.
      */
-    private long mNativeInstanceRuntimeShaderFactory;
+    private long mNativeInstanceRuntimeShaderBuilder;
 
     /**
      * Creates a new RuntimeShader.
@@ -50,80 +47,86 @@
      *                 on number of uniforms declared by sksl.
      * @param isOpaque True if all pixels have alpha 1.0f.
      */
-    public RuntimeShader(@NonNull String sksl, @Nullable byte[] uniforms, boolean isOpaque) {
-        this(sksl, uniforms, null, isOpaque, ColorSpace.get(ColorSpace.Named.SRGB));
-    }
-
-    /**
-     * Creates a new RuntimeShader.
-     *
-     * @param sksl The text of SKSL program to run on the GPU.
-     * @param uniforms Array of parameters passed by the SKSL shader. Array size depends
-     *                 on number of uniforms declared by sksl.
-     * @param shaderInputs Array of shaders passed to the SKSL shader. Array size depends
-     *                     on the number of input shaders declared in the sksl
-     * @param isOpaque True if all pixels have alpha 1.0f.
-     */
-    public  RuntimeShader(@NonNull String sksl, @Nullable byte[] uniforms,
-                          @Nullable Shader[] shaderInputs, boolean isOpaque) {
-        this(sksl, uniforms, shaderInputs, isOpaque, ColorSpace.get(ColorSpace.Named.SRGB));
-    }
-
-    private RuntimeShader(@NonNull String sksl, @Nullable byte[] uniforms,
-                          @Nullable Shader[] shaderInputs, boolean isOpaque,
-                          ColorSpace colorSpace) {
-        super(colorSpace);
-        mUniforms = uniforms;
-        mInputShaders = shaderInputs;
+    public RuntimeShader(@NonNull String sksl, boolean isOpaque) {
+        super(ColorSpace.get(ColorSpace.Named.SRGB));
         mIsOpaque = isOpaque;
-        mNativeInstanceRuntimeShaderFactory = nativeCreateShaderFactory(sksl);
-        NoImagePreloadHolder.sRegistry.registerNativeAllocation(this,
-                mNativeInstanceRuntimeShaderFactory);
+        mNativeInstanceRuntimeShaderBuilder = nativeCreateBuilder(sksl);
+        NoImagePreloadHolder.sRegistry.registerNativeAllocation(
+                this, mNativeInstanceRuntimeShaderBuilder);
     }
 
     /**
-     * Sets new value for shader parameters.
+     * Sets the uniform value corresponding to this shader.  If the shader does not have a uniform
+     * with that name or if the uniform is declared with a type other than float then an
+     * IllegalArgumentException is thrown.
      *
-     * @param uniforms Array of parameters passed by the SKSL shader. Array size depends
-     *                 on number of uniforms declared by mSksl.
+     * @param uniformName name matching the uniform declared in the SKSL shader
+     * @param value
      */
-    public void updateUniforms(@Nullable byte[] uniforms) {
-        mUniforms = uniforms;
+    public void setUniform(@NonNull String uniformName, float value) {
+        setUniform(uniformName, new float[] {value});
+    }
+
+    /**
+     * Sets the uniform value corresponding to this shader.  If the shader does not have a uniform
+     * with that name or if the uniform is declared with a type other than float2/vec2 then an
+     * IllegalArgumentException is thrown.
+     *
+     * @param uniformName name matching the uniform declared in the SKSL shader
+     * @param value1
+     * @param value2
+     */
+    public void setUniform(@NonNull String uniformName, float value1, float value2) {
+        setUniform(uniformName, new float[] {value1, value2});
+    }
+
+    /**
+     * Sets the uniform value corresponding to this shader.  If the shader does not have a uniform
+     * with that name or if the uniform is declared with a type other than a vecN/floatN where N is
+     * the size of the values array then an IllegalArgumentException is thrown.
+     *
+     * @param uniformName name matching the uniform declared in the SKSL shader
+     * @param values
+     */
+    public void setUniform(@NonNull String uniformName, float[] values) {
+        nativeUpdateUniforms(mNativeInstanceRuntimeShaderBuilder, uniformName, values);
         discardNativeInstance();
     }
 
     /**
-     * Sets new values for the shaders that serve as inputs to this shader.
+     * Sets the uniform shader that is declares as input to this shader.  If the shader does not
+     * have a uniform shader with that name then an IllegalArgumentException is thrown.
      *
-     * @param shaderInputs Array of Shaders passed into the SKSL shader. Array size depends
-     *                     on number of input shaders declared by sksl.
+     * @param shaderName name matching the uniform declared in the SKSL shader
+     * @param shader shader passed into the SKSL shader for sampling
      */
-    public void updateInputShaders(@Nullable Shader[] shaderInputs) {
-        mInputShaders = shaderInputs;
+    public void setInputShader(@NonNull String shaderName, @NonNull Shader shader) {
+        nativeUpdateShader(
+                    mNativeInstanceRuntimeShaderBuilder, shaderName, shader.getNativeInstance());
         discardNativeInstance();
     }
 
     /** @hide */
     @Override
     protected long createNativeInstance(long nativeMatrix, boolean filterFromPaint) {
-        long[] nativeShaders = mInputShaders.length > 0 ? new long[mInputShaders.length] : null;
-        for (int i = 0; i < mInputShaders.length; i++) {
-            nativeShaders[i] = mInputShaders[i].getNativeInstance(filterFromPaint);
-        }
-
-        return nativeCreate(mNativeInstanceRuntimeShaderFactory, nativeMatrix, mUniforms,
-                nativeShaders, colorSpace().getNativeInstance(), mIsOpaque);
+        return nativeCreateShader(mNativeInstanceRuntimeShaderBuilder, nativeMatrix, mIsOpaque);
     }
 
-    public long getNativeShaderFactory() {
-        return mNativeInstanceRuntimeShaderFactory;
+    public long getNativeShaderBuilder() {
+        return mNativeInstanceRuntimeShaderBuilder;
     }
 
-    private static native long nativeCreate(long shaderFactory, long matrix, byte[] inputs,
-            long[] shaderInputs, long colorSpaceHandle, boolean isOpaque);
-
-    private static native long nativeCreateShaderFactory(String sksl);
+    public boolean isOpaque() {
+        return mIsOpaque;
+    }
 
     private static native long nativeGetFinalizer();
+    private static native long nativeCreateBuilder(String sksl);
+    private static native long nativeCreateShader(
+            long shaderBuilder, long matrix, boolean isOpaque);
+    private static native void nativeUpdateUniforms(
+            long shaderBuilder, String uniformName, float[] uniforms);
+    private static native void nativeUpdateShader(
+            long shaderBuilder, String shaderName, long shader);
 }
 
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 48b474d..f1866cd 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -45,7 +45,6 @@
 import android.util.Base64;
 import android.util.LongSparseArray;
 import android.util.LruCache;
-import android.util.Pair;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
@@ -197,7 +196,11 @@
     // Must be the same as the C++ constant in core/jni/android/graphics/FontFamily.cpp
     /** @hide */
     public static final int RESOLVE_BY_FONT_TABLE = -1;
-    private static final String DEFAULT_FAMILY = "sans-serif";
+    /**
+     * The key of the default font family.
+     * @hide
+     */
+    public static final String DEFAULT_FAMILY = "sans-serif";
 
     // Style value for building typeface.
     private static final int STYLE_NORMAL = 0;
@@ -1139,18 +1142,19 @@
 
     /** @hide */
     @VisibleForTesting
-    public static void initSystemDefaultTypefaces(Map<String, Typeface> systemFontMap,
-            Map<String, FontFamily[]> fallbacks,
-            FontConfig.Alias[] aliases) {
+    public static void initSystemDefaultTypefaces(Map<String, FontFamily[]> fallbacks,
+            List<FontConfig.Alias> aliases,
+            Map<String, Typeface> outSystemFontMap) {
         for (Map.Entry<String, FontFamily[]> entry : fallbacks.entrySet()) {
-            systemFontMap.put(entry.getKey(), createFromFamilies(entry.getValue()));
+            outSystemFontMap.put(entry.getKey(), createFromFamilies(entry.getValue()));
         }
 
-        for (FontConfig.Alias alias : aliases) {
-            if (systemFontMap.containsKey(alias.getName())) {
+        for (int i = 0; i < aliases.size(); ++i) {
+            final FontConfig.Alias alias = aliases.get(i);
+            if (outSystemFontMap.containsKey(alias.getAliasName())) {
                 continue; // If alias and named family are conflict, use named family.
             }
-            final Typeface base = systemFontMap.get(alias.getToName());
+            final Typeface base = outSystemFontMap.get(alias.getReferName());
             if (base == null) {
                 // The missing target is a valid thing, some configuration don't have font files,
                 // e.g. wear devices. Just skip this alias.
@@ -1159,7 +1163,7 @@
             final int weight = alias.getWeight();
             final Typeface newFace = weight == 400 ? base :
                     new Typeface(nativeCreateWeightAlias(base.native_instance, weight));
-            systemFontMap.put(alias.getName(), newFace);
+            outSystemFontMap.put(alias.getAliasName(), newFace);
         }
     }
 
@@ -1339,11 +1343,11 @@
 
     /** @hide */
     public static void loadPreinstalledSystemFontMap() {
-        final HashMap<String, Typeface> systemFontMap = new HashMap<>();
-        Pair<FontConfig.Alias[], Map<String, FontFamily[]>> pair =
-                SystemFonts.initializePreinstalledFonts();
-        initSystemDefaultTypefaces(systemFontMap, pair.second, pair.first);
-        setSystemFontMap(systemFontMap);
+        final FontConfig fontConfig = SystemFonts.getSystemPreinstalledFontConfig();
+        final Map<String, FontFamily[]> fallback = SystemFonts.buildSystemFallback(fontConfig);
+        final Map<String, Typeface> typefaceMap =
+                SystemFonts.buildSystemTypefaces(fontConfig, fallback);
+        setSystemFontMap(typefaceMap);
     }
 
     static {
diff --git a/graphics/java/android/graphics/fonts/FontCustomizationParser.java b/graphics/java/android/graphics/fonts/FontCustomizationParser.java
index f95da82..1ad6fbe 100644
--- a/graphics/java/android/graphics/fonts/FontCustomizationParser.java
+++ b/graphics/java/android/graphics/fonts/FontCustomizationParser.java
@@ -16,18 +16,25 @@
 
 package android.graphics.fonts;
 
+import static android.text.FontConfig.Alias;
+import static android.text.FontConfig.Family;
+
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.graphics.FontListParser;
-import android.text.FontConfig;
 import android.util.Xml;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
-import java.util.HashSet;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 /**
  * Parser for font customization
@@ -39,8 +46,27 @@
      * Represents a customization XML
      */
     public static class Result {
-        ArrayList<FontConfig.Family> mAdditionalNamedFamilies = new ArrayList<>();
-        ArrayList<FontConfig.Alias> mAdditionalAliases = new ArrayList<>();
+        private final Map<String, Family> mAdditionalNamedFamilies;
+        private final List<Alias> mAdditionalAliases;
+
+        public Result() {
+            mAdditionalNamedFamilies = Collections.emptyMap();
+            mAdditionalAliases = Collections.emptyList();
+        }
+
+        public Result(Map<String, Family> additionalNamedFamilies,
+                List<Alias> additionalAliases) {
+            mAdditionalNamedFamilies = additionalNamedFamilies;
+            mAdditionalAliases = additionalAliases;
+        }
+
+        public Map<String, Family> getAdditionalNamedFamilies() {
+            return mAdditionalNamedFamilies;
+        }
+
+        public List<Alias> getAdditionalAliases() {
+            return mAdditionalAliases;
+        }
     }
 
     /**
@@ -48,56 +74,67 @@
      *
      * Caller must close the input stream
      */
-    public static Result parse(@NonNull InputStream in, @NonNull String fontDir)
-            throws XmlPullParserException, IOException {
+    public static Result parse(
+            @NonNull InputStream in,
+            @NonNull String fontDir,
+            @Nullable Map<String, File> updatableFontMap
+    ) throws XmlPullParserException, IOException {
         XmlPullParser parser = Xml.newPullParser();
         parser.setInput(in, null);
         parser.nextTag();
-        return readFamilies(parser, fontDir);
+        return readFamilies(parser, fontDir, updatableFontMap);
     }
 
-    private static void validate(Result result) {
-        HashSet<String> familyNames = new HashSet<>();
-        for (int i = 0; i < result.mAdditionalNamedFamilies.size(); ++i) {
-            final FontConfig.Family family = result.mAdditionalNamedFamilies.get(i);
-            final String name = family.getName();
+    private static Map<String, Family> validateAndTransformToMap(List<Family> families) {
+        HashMap<String, Family> namedFamily = new HashMap<>();
+        for (int i = 0; i < families.size(); ++i) {
+            final Family family = families.get(i);
+            final String name = family.getFallbackName();
             if (name == null) {
                 throw new IllegalArgumentException("new-named-family requires name attribute");
             }
-            if (!familyNames.add(name)) {
+            if (namedFamily.put(name, family) != null) {
                 throw new IllegalArgumentException(
                         "new-named-family requires unique name attribute");
             }
         }
+        return namedFamily;
     }
 
-    private static Result readFamilies(XmlPullParser parser, String fontDir)
-            throws XmlPullParserException, IOException {
-        Result out = new Result();
+    private static Result readFamilies(
+            @NonNull XmlPullParser parser,
+            @NonNull String fontDir,
+            @Nullable Map<String, File> updatableFontMap
+    ) throws XmlPullParserException, IOException {
+        List<Family> families = new ArrayList<>();
+        List<Alias> aliases = new ArrayList<>();
         parser.require(XmlPullParser.START_TAG, null, "fonts-modification");
         while (parser.next() != XmlPullParser.END_TAG) {
             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
             String tag = parser.getName();
             if (tag.equals("family")) {
-                readFamily(parser, fontDir, out);
+                readFamily(parser, fontDir, families, updatableFontMap);
             } else if (tag.equals("alias")) {
-                out.mAdditionalAliases.add(FontListParser.readAlias(parser));
+                aliases.add(FontListParser.readAlias(parser));
             } else {
                 FontListParser.skip(parser);
             }
         }
-        validate(out);
-        return out;
+        return new Result(validateAndTransformToMap(families), aliases);
     }
 
-    private static void readFamily(XmlPullParser parser, String fontDir, Result out)
+    private static void readFamily(
+            @NonNull XmlPullParser parser,
+            @NonNull String fontDir,
+            @NonNull List<Family> out,
+            @Nullable Map<String, File> updatableFontMap)
             throws XmlPullParserException, IOException {
         final String customizationType = parser.getAttributeValue(null, "customizationType");
         if (customizationType == null) {
             throw new IllegalArgumentException("customizationType must be specified");
         }
         if (customizationType.equals("new-named-family")) {
-            out.mAdditionalNamedFamilies.add(FontListParser.readFamily(parser, fontDir, null));
+            out.add(FontListParser.readFamily(parser, fontDir, updatableFontMap));
         } else {
             throw new IllegalArgumentException("Unknown customizationType=" + customizationType);
         }
diff --git a/graphics/java/android/graphics/fonts/FontFamily.java b/graphics/java/android/graphics/fonts/FontFamily.java
index 75ea120..2f0c26f 100644
--- a/graphics/java/android/graphics/fonts/FontFamily.java
+++ b/graphics/java/android/graphics/fonts/FontFamily.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntRange;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.text.FontConfig;
 
 import com.android.internal.util.Preconditions;
@@ -119,7 +120,7 @@
                 nAddFont(builderPtr, mFonts.get(i).getNativePtr());
             }
             final long ptr = nBuild(builderPtr, langTags, variant, isCustomFallback);
-            final FontFamily family = new FontFamily(mFonts, ptr);
+            final FontFamily family = new FontFamily(mFonts, langTags, variant, ptr);
             sFamilyRegistory.registerNativeAllocation(family, ptr);
             return family;
         }
@@ -138,15 +139,36 @@
     }
 
     private final ArrayList<Font> mFonts;
+    private final String mLangTags;
+    private final int mVariant;
     private final long mNativePtr;
 
     // Use Builder instead.
-    private FontFamily(@NonNull ArrayList<Font> fonts, long ptr) {
+    private FontFamily(@NonNull ArrayList<Font> fonts, String langTags, int variant, long ptr) {
         mFonts = fonts;
+        mLangTags = langTags;
+        mVariant = variant;
         mNativePtr = ptr;
     }
 
     /**
+     * Returns a BCP-47 compliant language tags associated with this font family.
+     * @hide
+     * @return a BCP-47 compliant language tag.
+     */
+    public @Nullable String getLangTags() {
+        return mLangTags;
+    }
+
+    /**
+     * @hide
+     * @return a family variant
+     */
+    public int getVariant() {
+        return mVariant;
+    }
+
+    /**
      * Returns a font
      *
      * @param index an index of the font
diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java
index 16a53c2..54167b4 100644
--- a/graphics/java/android/graphics/fonts/SystemFonts.java
+++ b/graphics/java/android/graphics/fonts/SystemFonts.java
@@ -23,11 +23,9 @@
 import android.text.FontConfig;
 import android.util.ArrayMap;
 import android.util.Log;
-import android.util.Pair;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
 
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -37,7 +35,6 @@
 import java.nio.ByteBuffer;
 import java.nio.channels.FileChannel;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -52,6 +49,11 @@
     private static final String TAG = "SystemFonts";
     private static final String DEFAULT_FAMILY = "sans-serif";
 
+    private static final String FONTS_XML = "/system/etc/fonts.xml";
+    private static final String SYSTEM_FONT_DIR = "/system/fonts/";
+    private static final String OEM_XML = "/product/etc/fonts_customization.xml";
+    private static final String OEM_FONT_DIR = "/product/fonts/";
+
     private SystemFonts() {}  // Do not instansiate.
 
     private static final Object LOCK = new Object();
@@ -88,12 +90,10 @@
     }
 
     private static @NonNull Set<Font> collectAllFonts() {
-        final FontCustomizationParser.Result oemCustomization =
-                readFontCustomization("/product/etc/fonts_customization.xml", "/product/fonts/");
-        Map<String, FontFamily[]> map = new ArrayMap<>();
         // TODO: use updated fonts
-        buildSystemFallback("/system/etc/fonts.xml", "/system/fonts/", null /* updatableFontDir */,
-                oemCustomization, map);
+        FontConfig fontConfig = getSystemPreinstalledFontConfig();
+        Map<String, FontFamily[]> map = buildSystemFallback(fontConfig);
+
         Set<Font> res = new HashSet<>();
         for (FontFamily[] families : map.values()) {
             for (FontFamily family : families) {
@@ -119,15 +119,16 @@
             @NonNull ArrayMap<String, ArrayList<FontFamily>> fallbackMap,
             @NonNull Map<String, ByteBuffer> cache) {
 
-        final String languageTags = xmlFamily.getLanguages();
-        final int variant = xmlFamily.getVariant();
+        final String languageTags = xmlFamily.getLocaleList().toLanguageTags();
+        final int variant = xmlFamily.getTextHeightVariant();
 
         final ArrayList<FontConfig.Font> defaultFonts = new ArrayList<>();
-        final ArrayMap<String, ArrayList<FontConfig.Font>> specificFallbackFonts = new ArrayMap<>();
+        final ArrayMap<String, ArrayList<FontConfig.Font>> specificFallbackFonts =
+                new ArrayMap<>();
 
         // Collect default fallback and specific fallback fonts.
         for (final FontConfig.Font font : xmlFamily.getFonts()) {
-            final String fallbackName = font.getFallbackFor();
+            final String fallbackName = font.getFallback();
             if (fallbackName == null) {
                 defaultFonts.add(font);
             } else {
@@ -141,19 +142,22 @@
         }
 
         final FontFamily defaultFamily = defaultFonts.isEmpty() ? null : createFontFamily(
-                xmlFamily.getName(), defaultFonts, languageTags, variant, cache);
+                xmlFamily.getFallbackName(), defaultFonts, languageTags, variant, cache);
 
         // Insert family into fallback map.
         for (int i = 0; i < fallbackMap.size(); i++) {
-            final ArrayList<FontConfig.Font> fallback =
-                    specificFallbackFonts.get(fallbackMap.keyAt(i));
+            String name = fallbackMap.keyAt(i);
+            final ArrayList<FontConfig.Font> fallback = specificFallbackFonts.get(name);
             if (fallback == null) {
-                if (defaultFamily != null) {
+                String familyName = xmlFamily.getFallbackName();
+                if (defaultFamily != null
+                        // do not add myself to the fallback chain.
+                        && (familyName == null || !familyName.equals(name))) {
                     fallbackMap.valueAt(i).add(defaultFamily);
                 }
             } else {
                 final FontFamily family = createFontFamily(
-                        xmlFamily.getName(), fallback, languageTags, variant, cache);
+                        xmlFamily.getFallbackName(), fallback, languageTags, variant, cache);
                 if (family != null) {
                     fallbackMap.valueAt(i).add(family);
                 } else if (defaultFamily != null) {
@@ -177,7 +181,7 @@
         FontFamily.Builder b = null;
         for (int i = 0; i < fonts.size(); i++) {
             final FontConfig.Font fontConfig = fonts.get(i);
-            final String fullPath = fontConfig.getFontName();
+            final String fullPath = fontConfig.getFilePath().getAbsolutePath();
             ByteBuffer buffer = cache.get(fullPath);
             if (buffer == null) {
                 if (cache.containsKey(fullPath)) {
@@ -193,11 +197,10 @@
             final Font font;
             try {
                 font = new Font.Builder(buffer, new File(fullPath), languageTags)
-                        .setWeight(fontConfig.getWeight())
-                        .setSlant(fontConfig.isItalic() ? FontStyle.FONT_SLANT_ITALIC
-                                : FontStyle.FONT_SLANT_UPRIGHT)
-                        .setTtcIndex(fontConfig.getTtcIndex())
-                        .setFontVariationSettings(fontConfig.getAxes())
+                        .setWeight(fontConfig.getStyle().getWeight())
+                        .setSlant(fontConfig.getStyle().getSlant())
+                        .setTtcIndex(fontConfig.getIndex())
+                        .setFontVariationSettings(fontConfig.getFontVariationSettings())
                         .build();
             } catch (IOException e) {
                 throw new RuntimeException(e);  // Never reaches here
@@ -215,10 +218,11 @@
     private static void appendNamedFamily(@NonNull FontConfig.Family xmlFamily,
             @NonNull HashMap<String, ByteBuffer> bufferCache,
             @NonNull ArrayMap<String, ArrayList<FontFamily>> fallbackListMap) {
-        final String familyName = xmlFamily.getName();
+        final String familyName = xmlFamily.getFallbackName();
         final FontFamily family = createFontFamily(
-                familyName, Arrays.asList(xmlFamily.getFonts()),
-                xmlFamily.getLanguages(), xmlFamily.getVariant(), bufferCache);
+                familyName, xmlFamily.getFontList(),
+                xmlFamily.getLocaleList().toLanguageTags(), xmlFamily.getTextHeightVariant(),
+                bufferCache);
         if (family == null) {
             return;
         }
@@ -228,116 +232,104 @@
     }
 
     /**
-     * @see #buildSystemFallback(String, String, String, FontCustomizationParser.Result, Map)
+     * Get the updated FontConfig.
+     *
+     * @param updatableFontMap a font mapping of updated font files.
      * @hide
      */
-    @VisibleForTesting
-    public static FontConfig.Alias[] buildSystemFallback(@NonNull String xmlPath,
-            @NonNull String fontDir,
-            @NonNull FontCustomizationParser.Result oemCustomization,
-            @NonNull Map<String, FontFamily[]> fallbackMap) {
-        return buildSystemFallback(xmlPath, fontDir, null /* updatableFontDir */,
-                oemCustomization, fallbackMap);
+    public static @NonNull FontConfig getSystemFontConfig(
+            @Nullable Map<String, File> updatableFontMap
+    ) {
+        return getSystemFontConfigInternal(FONTS_XML, SYSTEM_FONT_DIR, OEM_XML, OEM_FONT_DIR,
+                updatableFontMap);
     }
 
     /**
-     * Build the system fallback from xml file.
-     *
-     * @param xmlPath A full path string to the fonts.xml file.
-     * @param fontDir A full path string to the system font directory. This must end with
-     *                slash('/').
-     * @param updatableFontDir A full path string to the updatable system font directory. This
-     *                           must end with slash('/').
-     * @param fallbackMap An output system fallback map. Caller must pass empty map.
-     * @return a list of aliases
+     * Get the system preinstalled FontConfig.
+     * @hide
+     */
+    public static @NonNull FontConfig getSystemPreinstalledFontConfig() {
+        return getSystemFontConfigInternal(FONTS_XML, SYSTEM_FONT_DIR, OEM_XML, OEM_FONT_DIR, null);
+    }
+
+    /* package */ static @NonNull FontConfig getSystemFontConfigInternal(
+            @NonNull String fontsXml,
+            @NonNull String systemFontDir,
+            @Nullable String oemXml,
+            @Nullable String productFontDir,
+            @Nullable Map<String, File> updatableFontMap
+    ) {
+        try {
+            return FontListParser.parse(fontsXml, systemFontDir, oemXml, productFontDir,
+                                                updatableFontMap);
+        } catch (IOException e) {
+            Log.e(TAG, "Failed to open/read system font configurations.", e);
+            return new FontConfig(Collections.emptyList(), Collections.emptyList());
+        } catch (XmlPullParserException e) {
+            Log.e(TAG, "Failed to parse the system font configuration.", e);
+            return new FontConfig(Collections.emptyList(), Collections.emptyList());
+        }
+    }
+
+    /**
+     * Build the system fallback from FontConfig.
      * @hide
      */
     @VisibleForTesting
-    public static FontConfig.Alias[] buildSystemFallback(@NonNull String xmlPath,
-            @NonNull String fontDir,
-            @Nullable String updatableFontDir,
-            @NonNull FontCustomizationParser.Result oemCustomization,
-            @NonNull Map<String, FontFamily[]> fallbackMap) {
-        try {
-            final FileInputStream fontsIn = new FileInputStream(xmlPath);
-            final FontConfig fontConfig = FontListParser.parse(fontsIn, fontDir, updatableFontDir);
+    public static Map<String, FontFamily[]> buildSystemFallback(FontConfig fontConfig) {
+        final Map<String, FontFamily[]> fallbackMap = new HashMap<>();
+        final HashMap<String, ByteBuffer> bufferCache = new HashMap<>();
+        final List<FontConfig.Family> xmlFamilies = fontConfig.getFontFamilies();
 
-            final HashMap<String, ByteBuffer> bufferCache = new HashMap<String, ByteBuffer>();
-            final FontConfig.Family[] xmlFamilies = fontConfig.getFamilies();
-
-            final ArrayMap<String, ArrayList<FontFamily>> fallbackListMap = new ArrayMap<>();
-            // First traverse families which have a 'name' attribute to create fallback map.
-            for (final FontConfig.Family xmlFamily : xmlFamilies) {
-                final String familyName = xmlFamily.getName();
-                if (familyName == null) {
-                    continue;
-                }
-                appendNamedFamily(xmlFamily, bufferCache, fallbackListMap);
+        final ArrayMap<String, ArrayList<FontFamily>> fallbackListMap = new ArrayMap<>();
+        // First traverse families which have a 'name' attribute to create fallback map.
+        for (final FontConfig.Family xmlFamily : xmlFamilies) {
+            final String familyName = xmlFamily.getFallbackName();
+            if (familyName == null) {
+                continue;
             }
-
-            for (int i = 0; i < oemCustomization.mAdditionalNamedFamilies.size(); ++i) {
-                appendNamedFamily(oemCustomization.mAdditionalNamedFamilies.get(i),
-                        bufferCache, fallbackListMap);
-            }
-
-            // Then, add fallback fonts to the each fallback map.
-            for (int i = 0; i < xmlFamilies.length; i++) {
-                final FontConfig.Family xmlFamily = xmlFamilies[i];
-                // The first family (usually the sans-serif family) is always placed immediately
-                // after the primary family in the fallback.
-                if (i == 0 || xmlFamily.getName() == null) {
-                    pushFamilyToFallback(xmlFamily, fallbackListMap, bufferCache);
-                }
-            }
-
-            // Build the font map and fallback map.
-            for (int i = 0; i < fallbackListMap.size(); i++) {
-                final String fallbackName = fallbackListMap.keyAt(i);
-                final List<FontFamily> familyList = fallbackListMap.valueAt(i);
-                final FontFamily[] families = familyList.toArray(new FontFamily[familyList.size()]);
-
-                fallbackMap.put(fallbackName, families);
-            }
-
-            final ArrayList<FontConfig.Alias> list = new ArrayList<>();
-            list.addAll(Arrays.asList(fontConfig.getAliases()));
-            list.addAll(oemCustomization.mAdditionalAliases);
-            return list.toArray(new FontConfig.Alias[list.size()]);
-        } catch (IOException | XmlPullParserException e) {
-            Log.e(TAG, "Failed initialize system fallbacks.", e);
-            return ArrayUtils.emptyArray(FontConfig.Alias.class);
+            appendNamedFamily(xmlFamily, bufferCache, fallbackListMap);
         }
-    }
 
-    private static FontCustomizationParser.Result readFontCustomization(
-            @NonNull String customizeXml, @NonNull String customFontsDir) {
-        try (FileInputStream f = new FileInputStream(customizeXml)) {
-            return FontCustomizationParser.parse(f, customFontsDir);
-        } catch (IOException e) {
-            return new FontCustomizationParser.Result();
-        } catch (XmlPullParserException e) {
-            Log.e(TAG, "Failed to parse font customization XML", e);
-            return new FontCustomizationParser.Result();
+        // Then, add fallback fonts to the each fallback map.
+        for (int i = 0; i < xmlFamilies.size(); i++) {
+            final FontConfig.Family xmlFamily = xmlFamilies.get(i);
+            // The first family (usually the sans-serif family) is always placed immediately
+            // after the primary family in the fallback.
+            if (i == 0 || xmlFamily.getFallbackName() == null) {
+                pushFamilyToFallback(xmlFamily, fallbackListMap, bufferCache);
+            }
         }
+
+        // Build the font map and fallback map.
+        for (int i = 0; i < fallbackListMap.size(); i++) {
+            final String fallbackName = fallbackListMap.keyAt(i);
+            final List<FontFamily> familyList = fallbackListMap.valueAt(i);
+            fallbackMap.put(fallbackName, familyList.toArray(new FontFamily[0]));
+        }
+
+        return fallbackMap;
     }
 
-    /** @hide */
-    public static @NonNull Pair<FontConfig.Alias[], Map<String, FontFamily[]>>
-            initializePreinstalledFonts() {
-        return initializeSystemFonts(null);
+    /**
+     * Build the system Typeface mappings from FontConfig and FallbackMap.
+     * @hide
+     */
+    @VisibleForTesting
+    public static Map<String, Typeface> buildSystemTypefaces(
+            FontConfig fontConfig,
+            Map<String, FontFamily[]> fallbackMap) {
+        final HashMap<String, Typeface> result = new HashMap<>();
+        Typeface.initSystemDefaultTypefaces(fallbackMap, fontConfig.getAliases(), result);
+        return result;
     }
 
-    /** @hide */
-    public static Pair<FontConfig.Alias[], Map<String, FontFamily[]>>
-            initializeSystemFonts(@Nullable String updatableFontDir) {
-        final FontCustomizationParser.Result oemCustomization =
-                readFontCustomization("/product/etc/fonts_customization.xml", "/product/fonts/");
-        Map<String, FontFamily[]> map = new ArrayMap<>();
-        FontConfig.Alias[] aliases = buildSystemFallback("/system/etc/fonts.xml", "/system/fonts/",
-                updatableFontDir, oemCustomization, map);
+    /**
+     * @hide
+     */
+    public void resetFallbackMapping(Map<String, FontFamily[]> fallbackMap) {
         synchronized (LOCK) {
-            sFamilyMap = map;
+            sFamilyMap = fallbackMap;
         }
-        return new Pair(aliases, map);
     }
 }
diff --git a/keystore/java/android/security/AuthTokenUtils.java b/keystore/java/android/security/AuthTokenUtils.java
new file mode 100644
index 0000000..14d6626
--- /dev/null
+++ b/keystore/java/android/security/AuthTokenUtils.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import android.annotation.NonNull;
+import android.hardware.security.keymint.HardwareAuthToken;
+import android.hardware.security.keymint.Timestamp;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * @hide This Utils class provides method(s) for AuthToken conversion.
+ */
+public class AuthTokenUtils {
+
+    private AuthTokenUtils(){
+    }
+
+    /**
+     * Build a HardwareAuthToken from a byte array
+     * @param array byte array representing an auth token
+     * @return HardwareAuthToken representation of an auth token
+     */
+    public static @NonNull HardwareAuthToken toHardwareAuthToken(@NonNull byte[] array) {
+        final HardwareAuthToken hardwareAuthToken = new HardwareAuthToken();
+
+        // First byte is version, which does not exist in HardwareAuthToken anymore
+        // Next 8 bytes is the challenge.
+        hardwareAuthToken.challenge =
+                ByteBuffer.wrap(array, 1, 8).order(ByteOrder.nativeOrder()).getLong();
+
+        // Next 8 bytes is the userId
+        hardwareAuthToken.userId =
+                ByteBuffer.wrap(array, 9, 8).order(ByteOrder.nativeOrder()).getLong();
+
+        // Next 8 bytes is the authenticatorId.
+        hardwareAuthToken.authenticatorId =
+                ByteBuffer.wrap(array, 17, 8).order(ByteOrder.nativeOrder()).getLong();
+
+        // while the other fields are in machine byte order, authenticatorType and timestamp
+        // are in network byte order.
+        // Next 4 bytes is the authenticatorType.
+        hardwareAuthToken.authenticatorType =
+                ByteBuffer.wrap(array, 25, 4).order(ByteOrder.BIG_ENDIAN).getInt();
+        // Next 8 bytes is the timestamp.
+        final Timestamp timestamp = new Timestamp();
+        timestamp.milliSeconds =
+                ByteBuffer.wrap(array, 29, 8).order(ByteOrder.BIG_ENDIAN).getLong();
+        hardwareAuthToken.timestamp = timestamp;
+
+        // Last 32 bytes is the mac, 37:69
+        hardwareAuthToken.mac = new byte[32];
+        System.arraycopy(array, 37 /* srcPos */,
+                hardwareAuthToken.mac,
+                0 /* destPos */,
+                32 /* length */);
+
+        return hardwareAuthToken;
+    }
+}
diff --git a/keystore/java/android/security/Authorization.java b/keystore/java/android/security/Authorization.java
new file mode 100644
index 0000000..1fde2b5
--- /dev/null
+++ b/keystore/java/android/security/Authorization.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import android.annotation.NonNull;
+import android.hardware.security.keymint.HardwareAuthToken;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
+import android.security.authorization.IKeystoreAuthorization;
+import android.system.keystore2.ResponseCode;
+import android.util.Log;
+
+/**
+ * @hide This is the client side for IKeystoreAuthorization AIDL.
+ * It shall only be used by biometric authentication providers and Gatekeeper.
+ */
+public class Authorization {
+    private static final String TAG = "KeystoreAuthorization";
+    private static IKeystoreAuthorization sIKeystoreAuthorization;
+
+    public static final int SYSTEM_ERROR = ResponseCode.SYSTEM_ERROR;
+
+    public Authorization() {
+        sIKeystoreAuthorization = null;
+    }
+
+    private static synchronized IKeystoreAuthorization getService() {
+        if (sIKeystoreAuthorization == null) {
+            sIKeystoreAuthorization = IKeystoreAuthorization.Stub.asInterface(
+                    ServiceManager.checkService("android.security.authorization"));
+        }
+        return sIKeystoreAuthorization;
+    }
+
+    /**
+     * Adds an auth token to keystore2.
+     *
+     * @param authToken created by Android authenticators.
+     * @return 0 if successful or {@code ResponseCode.SYSTEM_ERROR}.
+     */
+    public int addAuthToken(@NonNull HardwareAuthToken authToken) {
+        if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
+        try {
+            getService().addAuthToken(authToken);
+            return 0;
+        } catch (RemoteException e) {
+            Log.w(TAG, "Can not connect to keystore", e);
+            return SYSTEM_ERROR;
+        } catch (ServiceSpecificException e) {
+            return e.errorCode;
+        }
+    }
+
+    /**
+     * Add an auth token to Keystore 2.0 in the legacy serialized auth token format.
+     * @param authToken
+     * @return 0 if successful or a {@code ResponseCode}.
+     */
+    public int addAuthToken(@NonNull byte[] authToken) {
+        return addAuthToken(AuthTokenUtils.toHardwareAuthToken(authToken));
+    }
+
+}
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 2f444b3..97819c5 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -17,10 +17,13 @@
 
 import static android.security.Credentials.ACTION_MANAGE_CREDENTIALS;
 
+import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.TestApi;
 import android.annotation.WorkerThread;
 import android.app.Activity;
 import android.app.PendingIntent;
@@ -41,6 +44,7 @@
 import android.security.keystore.AndroidKeyStoreProvider;
 import android.security.keystore.KeyPermanentlyInvalidatedException;
 import android.security.keystore.KeyProperties;
+import android.util.Log;
 
 import com.android.org.conscrypt.TrustedCertificateStore;
 
@@ -105,6 +109,11 @@
 public final class KeyChain {
 
     /**
+     * @hide
+     */
+    public static final String LOG = "KeyChain";
+
+    /**
      * @hide Also used by KeyChainService implementation
      */
     public static final String ACCOUNT_TYPE = "com.android.keychain";
@@ -579,6 +588,55 @@
         activity.startActivity(intent);
     }
 
+    /**
+     * Set a credential management app. The credential management app has the ability to manage
+     * the user's KeyChain credentials on unmanaged devices.
+     *
+     * <p>There can only be one credential management on the device. If another app requests to
+     * become the credential management app, then the existing credential management app will
+     * no longer be able to manage credentials.
+     *
+     * @param packageName The package name of the credential management app
+     * @param authenticationPolicy The authentication policy of the credential management app. This
+     *                             policy determines which alias for a private key and certificate
+     *                             pair should be used for authentication.
+     * @return {@code true} if the credential management app was successfully added.
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(Manifest.permission.MANAGE_CREDENTIAL_MANAGEMENT_APP)
+    public static boolean setCredentialManagementApp(@NonNull Context context,
+            @NonNull String packageName, @NonNull AppUriAuthenticationPolicy authenticationPolicy) {
+        try (KeyChainConnection keyChainConnection = KeyChain.bind(context)) {
+            keyChainConnection.getService()
+                    .setCredentialManagementApp(packageName, authenticationPolicy);
+            return true;
+        } catch (RemoteException | InterruptedException e) {
+            Log.w(LOG, "Set credential management app failed", e);
+            Thread.currentThread().interrupt();
+            return false;
+        }
+    }
+
+    /**
+     * Remove the user's KeyChain credentials on unmanaged devices.
+     *
+     * @return {@code true} if the credential management app was successfully removed.
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(Manifest.permission.MANAGE_CREDENTIAL_MANAGEMENT_APP)
+    public static boolean removeCredentialManagementApp(@NonNull Context context) {
+        try (KeyChainConnection keyChainConnection = KeyChain.bind(context)) {
+            keyChainConnection.getService().removeCredentialManagementApp();
+            return true;
+        } catch (RemoteException | InterruptedException e) {
+            Log.w(LOG, "Remove credential management app failed", e);
+            Thread.currentThread().interrupt();
+            return false;
+        }
+    }
+
     private static class AliasResponse extends IKeyChainAliasCallback.Stub {
         private final KeyChainAliasCallback keyChainAliasResponse;
         private AliasResponse(KeyChainAliasCallback keyChainAliasResponse) {
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index c70c986..4a67135 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -996,6 +996,7 @@
      */
     public int addAuthToken(byte[] authToken) {
         try {
+            new Authorization().addAuthToken(authToken);
             return mBinder.addAuthToken(authToken);
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
diff --git a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationChunkedStreamer.java b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationChunkedStreamer.java
index 6c733ba..33e8ded 100644
--- a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationChunkedStreamer.java
+++ b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationChunkedStreamer.java
@@ -139,7 +139,9 @@
             int inputConsumed = ArrayUtils.copy(input, inputOffset, mChunk, mChunkLength,
                     inputLength);
             inputLength -= inputConsumed;
-            inputOffset += inputOffset;
+            inputOffset += inputConsumed;
+            mChunkLength += inputConsumed;
+            if (mChunkLength < mChunkSizeMax) return output;
             byte[] o = mKeyStoreStream.update(mChunk);
             if (o != null) {
                 output = ArrayUtils.concat(output, o);
diff --git a/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json b/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json
index 0290d9f..2cfb13e 100644
--- a/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json
+++ b/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json
@@ -1,6 +1,12 @@
 {
   "version": "1.0.0",
   "messages": {
+    "-2076257741": {
+      "message": "Transition requested: %s %s",
+      "level": "VERBOSE",
+      "group": "WM_SHELL_TRANSITIONS",
+      "at": "com\/android\/wm\/shell\/transition\/Transitions.java"
+    },
     "-1683614271": {
       "message": "Existing task: id=%d component=%s",
       "level": "VERBOSE",
@@ -133,12 +139,6 @@
       "group": "WM_SHELL_TASK_ORG",
       "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
     },
-    "846958769": {
-      "message": "Transition requested: type=%d %s",
-      "level": "VERBOSE",
-      "group": "WM_SHELL_TRANSITIONS",
-      "at": "com\/android\/wm\/shell\/transition\/Transitions.java"
-    },
     "900599280": {
       "message": "Can't pair unresizeable tasks task1.isResizeable=%b task1.isResizeable=%b",
       "level": "ERROR",
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java
index 0146b72..7aedc1b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java
@@ -71,6 +71,7 @@
 
     @Override
     public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
+        if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
         final SurfaceControl leash = mLeashByTaskId.get(taskInfo.taskId);
         final Point positionInParent = taskInfo.positionInParent;
         mSyncQueue.runInSync(t -> t.setPosition(leash, positionInParent.x, positionInParent.y));
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 faa4a0e..c9b38d0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -262,12 +262,6 @@
         synchronized (mLock) {
             ProtoLog.v(WM_SHELL_TASK_ORG, "Task info changed taskId=%d", taskInfo.taskId);
             final TaskAppearedInfo data = mTasks.get(taskInfo.taskId);
-            if (data == null) {
-                // TODO(b/171749427): It means onTaskInfoChanged send before onTaskAppeared or
-                //  after onTaskVanished, it should be fixed in controller side.
-                return;
-            }
-
             final TaskListener oldListener = getTaskListener(data.getTaskInfo());
             final TaskListener newListener = getTaskListener(taskInfo);
             mTasks.put(taskInfo.taskId, new TaskAppearedInfo(taskInfo, data.getLeash()));
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
index 8d0e965..dd43139 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
@@ -252,7 +252,9 @@
         mTaskOrganizer.setInterceptBackPressedOnTaskRoot(mTaskToken, true);
         // TODO: Synchronize show with the resize
         onLocationChanged();
-        setResizeBackgroundColor(taskInfo.taskDescription.getBackgroundColor());
+        if (taskInfo.taskDescription != null) {
+            setResizeBackgroundColor(taskInfo.taskDescription.getBackgroundColor());
+        }
 
         if (mListener != null) {
             mListenerExecutor.execute(() -> {
@@ -279,8 +281,9 @@
 
     @Override
     public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
-        mTaskInfo.taskDescription = taskInfo.taskDescription;
-        setResizeBackgroundColor(taskInfo.taskDescription.getBackgroundColor());
+        if (taskInfo.taskDescription != null) {
+            setResizeBackgroundColor(taskInfo.taskDescription.getBackgroundColor());
+        }
     }
 
     @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/SplitScreenTransitions.java
index 94b2cc0..d066cf9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/SplitScreenTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/SplitScreenTransitions.java
@@ -36,6 +36,7 @@
 import android.view.SurfaceControl;
 import android.view.WindowManager;
 import android.window.TransitionInfo;
+import android.window.TransitionRequestInfo;
 import android.window.WindowContainerTransaction;
 
 import com.android.wm.shell.common.TransactionPool;
@@ -76,9 +77,11 @@
     }
 
     @Override
-    public WindowContainerTransaction handleRequest(@WindowManager.TransitionType int type,
-            @NonNull IBinder transition, @Nullable ActivityManager.RunningTaskInfo triggerTask) {
+    public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
+            @Nullable TransitionRequestInfo request) {
         WindowContainerTransaction out = null;
+        final ActivityManager.RunningTaskInfo triggerTask = request.getTriggerTask();
+        final @WindowManager.TransitionType int type = request.getType();
         if (mSplitScreen.isDividerVisible()) {
             // try to handle everything while in split-screen
             out = new WindowContainerTransaction();
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 821a007..e958648 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
@@ -49,9 +49,9 @@
     void stopOneHanded();
 
     /**
-     * Exits one handed mode with {@link OneHandedEvents}.
+     * Exits one handed mode with {@link OneHandedUiEventLogger}.
      */
-    void stopOneHanded(int event);
+    void stopOneHanded(int uiEvent);
 
     /**
      * Set navigation 3 button mode enabled or disabled by users.
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 48d6a7b..eaa704f 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
@@ -37,6 +37,7 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
+import com.android.internal.logging.UiEventLogger;
 import com.android.wm.shell.R;
 import com.android.wm.shell.common.DisplayChangeController;
 import com.android.wm.shell.common.DisplayController;
@@ -47,7 +48,6 @@
 import com.android.wm.shell.onehanded.OneHandedGestureHandler.OneHandedGestureEventCallback;
 
 import java.io.PrintWriter;
-import java.util.concurrent.Executor;
 
 /**
  * Manages and manipulates the one handed states, transitions, and gesture for phones.
@@ -73,6 +73,8 @@
     private final OneHandedTimeoutHandler mTimeoutHandler;
     private final OneHandedTouchHandler mTouchHandler;
     private final OneHandedTutorialHandler mTutorialHandler;
+    private final OneHandedUiEventLogger mOneHandedUiEventLogger;
+    private final TaskStackListenerImpl mTaskStackListener;
     private final IOverlayManager mOverlayManager;
     private final ShellExecutor mMainExecutor;
     private final Handler mMainHandler;
@@ -117,15 +119,28 @@
                 }
             };
 
+    private final TaskStackListenerCallback mTaskStackListenerCallback =
+            new TaskStackListenerCallback() {
+                @Override
+                public void onTaskCreated(int taskId, ComponentName componentName) {
+                    stopOneHanded(OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT);
+                }
+
+                @Override
+                public void onTaskMovedToFront(int taskId) {
+                    stopOneHanded(OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT);
+                }
+            };
+
+
     /**
      * Creates {@link OneHanded}, returns {@code null} if the feature is not supported.
      */
     @Nullable
     public static OneHanded create(
             Context context, DisplayController displayController,
-            TaskStackListenerImpl taskStackListener,
-            ShellExecutor mainExecutor,
-            Handler mainHandler) {
+            TaskStackListenerImpl taskStackListener, UiEventLogger uiEventLogger,
+            ShellExecutor mainExecutor, Handler mainHandler) {
         if (!SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false)) {
             Slog.w(TAG, "Device doesn't support OneHanded feature");
             return null;
@@ -145,12 +160,13 @@
         OneHandedDisplayAreaOrganizer organizer = new OneHandedDisplayAreaOrganizer(
                 context, displayController, animationController, tutorialHandler,
                 oneHandedBackgroundPanelOrganizer, mainExecutor);
+        OneHandedUiEventLogger oneHandedUiEventsLogger = new OneHandedUiEventLogger(uiEventLogger);
         IOverlayManager overlayManager = IOverlayManager.Stub.asInterface(
                 ServiceManager.getService(Context.OVERLAY_SERVICE));
         return new OneHandedController(context, displayController,
                 oneHandedBackgroundPanelOrganizer, organizer, touchHandler, tutorialHandler,
-                gestureHandler, timeoutHandler, overlayManager, taskStackListener, mainExecutor,
-                mainHandler).mImpl;
+                gestureHandler, timeoutHandler, oneHandedUiEventsLogger, overlayManager,
+                taskStackListener, mainExecutor, mainHandler).mImpl;
     }
 
     @VisibleForTesting
@@ -162,6 +178,7 @@
             OneHandedTutorialHandler tutorialHandler,
             OneHandedGestureHandler gestureHandler,
             OneHandedTimeoutHandler timeoutHandler,
+            OneHandedUiEventLogger uiEventsLogger,
             IOverlayManager overlayManager,
             TaskStackListenerImpl taskStackListener,
             ShellExecutor mainExecutor,
@@ -176,6 +193,8 @@
         mOverlayManager = overlayManager;
         mMainExecutor = mainExecutor;
         mMainHandler = mainHandler;
+        mOneHandedUiEventLogger = uiEventsLogger;
+        mTaskStackListener = taskStackListener;
 
         final float offsetPercentageConfig = context.getResources().getFraction(
                 R.fraction.config_one_handed_offset, 1, 1);
@@ -203,19 +222,6 @@
         setupGesturalOverlay();
         updateSettings();
 
-        taskStackListener.addListener(
-                new TaskStackListenerCallback() {
-                    @Override
-                    public void onTaskCreated(int taskId, ComponentName componentName) {
-                        stopOneHanded(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT);
-                    }
-
-                    @Override
-                    public void onTaskMovedToFront(int taskId) {
-                        stopOneHanded(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT);
-                    }
-                });
-
         mAccessibilityManager = (AccessibilityManager)
                 context.getSystemService(Context.ACCESSIBILITY_SERVICE);
         mAccessibilityManager.addAccessibilityStateChangeListener(
@@ -234,6 +240,11 @@
      * Set one handed enabled or disabled by when user update settings
      */
     void setTaskChangeToExit(boolean enabled) {
+        if (enabled) {
+            mTaskStackListener.addListener(mTaskStackListenerCallback);
+        } else {
+            mTaskStackListener.removeListener(mTaskStackListenerCallback);
+        }
         mTaskChangeToExit = enabled;
     }
 
@@ -252,7 +263,8 @@
             mDisplayAreaOrganizer.scheduleOffset(0, yOffSet);
             mTimeoutHandler.resetTimer();
 
-            OneHandedEvents.writeEvent(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_GESTURE_IN);
+            mOneHandedUiEventLogger.writeEvent(
+                    OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_GESTURE_IN);
         }
     }
 
@@ -264,17 +276,12 @@
         }
     }
 
-    private void stopOneHanded(int event) {
-        if (!mTaskChangeToExit && event == OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT) {
-            //Task change exit not enable, do nothing and return here.
-            return;
-        }
-
+    private void stopOneHanded(int uiEvent) {
         if (mDisplayAreaOrganizer.isInOneHanded()) {
-            OneHandedEvents.writeEvent(event);
+            mDisplayAreaOrganizer.scheduleOffset(0, 0);
+            mTimeoutHandler.removeTimer();
+            mOneHandedUiEventLogger.writeEvent(uiEvent);
         }
-
-        stopOneHanded();
     }
 
     private void setThreeButtonModeEnabled(boolean enabled) {
@@ -292,11 +299,14 @@
 
     private void setupCallback() {
         mTouchHandler.registerTouchEventListener(() ->
-                stopOneHanded(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_OVERSPACE_OUT));
+                stopOneHanded(OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_OVERSPACE_OUT));
         mDisplayAreaOrganizer.registerTransitionCallback(mTouchHandler);
         mDisplayAreaOrganizer.registerTransitionCallback(mGestureHandler);
         mDisplayAreaOrganizer.registerTransitionCallback(mTutorialHandler);
         mDisplayAreaOrganizer.registerTransitionCallback(mBackgroundPanelOrganizer);
+        if (mTaskChangeToExit) {
+            mTaskStackListener.addListener(mTaskStackListenerCallback);
+        }
     }
 
     private void setupSettingObservers() {
@@ -334,9 +344,9 @@
     private void onEnabledSettingChanged() {
         final boolean enabled = OneHandedSettingsUtil.getSettingsOneHandedModeEnabled(
                 mContext.getContentResolver());
-        OneHandedEvents.writeEvent(enabled
-                ? OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_ENABLED_ON
-                : OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_ENABLED_OFF);
+        mOneHandedUiEventLogger.writeEvent(enabled
+                ? OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_ENABLED_ON
+                : OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_ENABLED_OFF);
 
         setOneHandedEnabled(enabled);
 
@@ -349,25 +359,25 @@
     private void onTimeoutSettingChanged() {
         final int newTimeout = OneHandedSettingsUtil.getSettingsOneHandedModeTimeout(
                 mContext.getContentResolver());
-        int metricsId = OneHandedEvents.OneHandedSettingsTogglesEvent.INVALID.getId();
+        int metricsId = OneHandedUiEventLogger.OneHandedSettingsTogglesEvent.INVALID.getId();
         switch (newTimeout) {
             case OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_NEVER:
-                metricsId = OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_NEVER;
+                metricsId = OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_NEVER;
                 break;
             case OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_SHORT_IN_SECONDS:
-                metricsId = OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_4;
+                metricsId = OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_4;
                 break;
             case OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS:
-                metricsId = OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_8;
+                metricsId = OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_8;
                 break;
             case OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_LONG_IN_SECONDS:
-                metricsId = OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_12;
+                metricsId = OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_12;
                 break;
             default:
                 // do nothing
                 break;
         }
-        OneHandedEvents.writeEvent(metricsId);
+        mOneHandedUiEventLogger.writeEvent(metricsId);
 
         if (mTimeoutHandler != null) {
             mTimeoutHandler.setTimeout(newTimeout);
@@ -377,9 +387,9 @@
     private void onTaskChangeExitSettingChanged() {
         final boolean enabled = OneHandedSettingsUtil.getSettingsTapsAppToExit(
                 mContext.getContentResolver());
-        OneHandedEvents.writeEvent(enabled
-                ? OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_APP_TAPS_EXIT_ON
-                : OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_APP_TAPS_EXIT_OFF);
+        mOneHandedUiEventLogger.writeEvent(enabled
+                ? OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_APP_TAPS_EXIT_ON
+                : OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_APP_TAPS_EXIT_OFF);
 
         setTaskChangeToExit(enabled);
     }
@@ -397,9 +407,8 @@
     }
 
     private void setupTimeoutListener() {
-        mTimeoutHandler.registerTimeoutListener(timeoutTime -> {
-            stopOneHanded(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_TIMEOUT_OUT);
-        });
+        mTimeoutHandler.registerTimeoutListener(timeoutTime -> stopOneHanded(
+                OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_TIMEOUT_OUT));
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedEvents.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedUiEventLogger.java
similarity index 80%
rename from libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedEvents.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedUiEventLogger.java
index 79ddd2b..38ffb07 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedEvents.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedUiEventLogger.java
@@ -19,17 +19,13 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.UiEvent;
 import com.android.internal.logging.UiEventLogger;
-import com.android.internal.logging.UiEventLoggerImpl;
 
 /**
- *  Interesting events related to the One-Handed.
+ *  Helper class that ends OneHanded mode log to UiEvent, see also go/uievent
  */
-public class OneHandedEvents {
-    private static final String TAG = "OneHandedEvents";
-
-    public static Callback sCallback;
-    @VisibleForTesting
-    static UiEventLogger sUiEventLogger = new UiEventLoggerImpl();
+public class OneHandedUiEventLogger {
+    private static final String TAG = "OneHandedUiEventLogger";
+    private final UiEventLogger mUiEventLogger;
 
     /**
      * One-Handed event types
@@ -76,6 +72,10 @@
             "one_handed_settings_timeout_seconds_12"
     };
 
+    public OneHandedUiEventLogger(UiEventLogger uiEventLogger) {
+        mUiEventLogger = uiEventLogger;
+    }
+
     /**
      * Events definition that related to One-Handed gestures.
      */
@@ -112,6 +112,7 @@
             mId = id;
         }
 
+        @Override
         public int getId() {
             return mId;
         }
@@ -159,6 +160,7 @@
             mId = id;
         }
 
+        @Override
         public int getId() {
             return mId;
         }
@@ -169,12 +171,8 @@
      * Logs an event to the system log, to sCallback if present, and to the logEvent destinations.
      * @param tag One of the EVENT_* codes above.
      */
-    public static void writeEvent(int tag) {
-        final long time = System.currentTimeMillis();
+    public void writeEvent(int tag) {
         logEvent(tag);
-        if (sCallback != null) {
-            sCallback.writeEvent(time, tag);
-        }
     }
 
     /**
@@ -183,94 +181,75 @@
      * @return String a readable description of the event.  Begins "writeEvent <tag_description>"
      * if the tag is valid.
      */
-    public static String logEvent(int event) {
-        if (event >= EVENT_TAGS.length) {
-            return "";
-        }
-        final StringBuilder sb = new StringBuilder("writeEvent ").append(EVENT_TAGS[event]);
+    private void logEvent(int event) {
         switch (event) {
-            // Triggers
             case EVENT_ONE_HANDED_TRIGGER_GESTURE_IN:
-                sUiEventLogger.log(OneHandedTriggerEvent.ONE_HANDED_TRIGGER_GESTURE_IN);
+                mUiEventLogger.log(OneHandedTriggerEvent.ONE_HANDED_TRIGGER_GESTURE_IN);
                 break;
             case EVENT_ONE_HANDED_TRIGGER_GESTURE_OUT:
-                sUiEventLogger.log(OneHandedTriggerEvent.ONE_HANDED_TRIGGER_GESTURE_OUT);
+                mUiEventLogger.log(OneHandedTriggerEvent.ONE_HANDED_TRIGGER_GESTURE_OUT);
                 break;
             case EVENT_ONE_HANDED_TRIGGER_OVERSPACE_OUT:
-                sUiEventLogger.log(OneHandedTriggerEvent.ONE_HANDED_TRIGGER_OVERSPACE_OUT);
+                mUiEventLogger.log(OneHandedTriggerEvent.ONE_HANDED_TRIGGER_OVERSPACE_OUT);
                 break;
             case EVENT_ONE_HANDED_TRIGGER_POP_IME_OUT:
-                sUiEventLogger.log(OneHandedTriggerEvent.ONE_HANDED_TRIGGER_POP_IME_OUT);
+                mUiEventLogger.log(OneHandedTriggerEvent.ONE_HANDED_TRIGGER_POP_IME_OUT);
                 break;
             case EVENT_ONE_HANDED_TRIGGER_ROTATION_OUT:
-                sUiEventLogger.log(OneHandedTriggerEvent.ONE_HANDED_TRIGGER_ROTATION_OUT);
+                mUiEventLogger.log(OneHandedTriggerEvent.ONE_HANDED_TRIGGER_ROTATION_OUT);
                 break;
             case EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT:
-                sUiEventLogger.log(OneHandedTriggerEvent.ONE_HANDED_TRIGGER_APP_TAPS_OUT);
+                mUiEventLogger.log(OneHandedTriggerEvent.ONE_HANDED_TRIGGER_APP_TAPS_OUT);
                 break;
             case EVENT_ONE_HANDED_TRIGGER_TIMEOUT_OUT:
-                sUiEventLogger.log(OneHandedTriggerEvent.ONE_HANDED_TRIGGER_TIMEOUT_OUT);
+                mUiEventLogger.log(OneHandedTriggerEvent.ONE_HANDED_TRIGGER_TIMEOUT_OUT);
                 break;
             case EVENT_ONE_HANDED_TRIGGER_SCREEN_OFF_OUT:
-                sUiEventLogger.log(OneHandedTriggerEvent.ONE_HANDED_TRIGGER_SCREEN_OFF_OUT);
+                mUiEventLogger.log(OneHandedTriggerEvent.ONE_HANDED_TRIGGER_SCREEN_OFF_OUT);
                 break;
-            // Settings
             case EVENT_ONE_HANDED_SETTINGS_ENABLED_ON:
-                sUiEventLogger.log(OneHandedSettingsTogglesEvent
+                mUiEventLogger.log(OneHandedSettingsTogglesEvent
                         .ONE_HANDED_SETTINGS_TOGGLES_ENABLED_ON);
                 break;
             case EVENT_ONE_HANDED_SETTINGS_ENABLED_OFF:
-                sUiEventLogger.log(OneHandedSettingsTogglesEvent
+                mUiEventLogger.log(OneHandedSettingsTogglesEvent
                         .ONE_HANDED_SETTINGS_TOGGLES_ENABLED_OFF);
                 break;
             case EVENT_ONE_HANDED_SETTINGS_APP_TAPS_EXIT_ON:
-                sUiEventLogger.log(OneHandedSettingsTogglesEvent
+                mUiEventLogger.log(OneHandedSettingsTogglesEvent
                         .ONE_HANDED_SETTINGS_TOGGLES_APP_TAPS_EXIT_ON);
                 break;
             case EVENT_ONE_HANDED_SETTINGS_APP_TAPS_EXIT_OFF:
-                sUiEventLogger.log(OneHandedSettingsTogglesEvent
+                mUiEventLogger.log(OneHandedSettingsTogglesEvent
                         .ONE_HANDED_SETTINGS_TOGGLES_APP_TAPS_EXIT_OFF);
                 break;
             case EVENT_ONE_HANDED_SETTINGS_TIMEOUT_EXIT_ON:
-                sUiEventLogger.log(OneHandedSettingsTogglesEvent
+                mUiEventLogger.log(OneHandedSettingsTogglesEvent
                         .ONE_HANDED_SETTINGS_TOGGLES_TIMEOUT_EXIT_ON);
                 break;
             case EVENT_ONE_HANDED_SETTINGS_TIMEOUT_EXIT_OFF:
-                sUiEventLogger.log(OneHandedSettingsTogglesEvent
+                mUiEventLogger.log(OneHandedSettingsTogglesEvent
                         .ONE_HANDED_SETTINGS_TOGGLES_TIMEOUT_EXIT_OFF);
                 break;
             case EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_NEVER:
-                sUiEventLogger.log(OneHandedSettingsTogglesEvent
+                mUiEventLogger.log(OneHandedSettingsTogglesEvent
                         .ONE_HANDED_SETTINGS_TOGGLES_TIMEOUT_SECONDS_NEVER);
                 break;
             case EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_4:
-                sUiEventLogger.log(OneHandedSettingsTogglesEvent
+                mUiEventLogger.log(OneHandedSettingsTogglesEvent
                         .ONE_HANDED_SETTINGS_TOGGLES_TIMEOUT_SECONDS_4);
                 break;
             case EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_8:
-                sUiEventLogger.log(OneHandedSettingsTogglesEvent
+                mUiEventLogger.log(OneHandedSettingsTogglesEvent
                         .ONE_HANDED_SETTINGS_TOGGLES_TIMEOUT_SECONDS_8);
                 break;
             case EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_12:
-                sUiEventLogger.log(OneHandedSettingsTogglesEvent
+                mUiEventLogger.log(OneHandedSettingsTogglesEvent
                         .ONE_HANDED_SETTINGS_TOGGLES_TIMEOUT_SECONDS_12);
                 break;
             default:
                 // Do nothing
                 break;
         }
-        return sb.toString();
-    }
-
-    /**
-     * An interface for logging an event to the system log, if Callback present.
-     */
-    public interface Callback {
-        /**
-         *
-         * @param time System current time.
-         * @param tag Event tag.
-         */
-        void writeEvent(long time, int tag);
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java
index de3bb29..f8b4dd9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java
@@ -41,12 +41,12 @@
     }
 
     public void setTaskInfo(TaskInfo taskInfo) {
-        if (taskInfo == null) {
-            mPackageName = null;
-            mPackageUid = INVALID_PACKAGE_UID;
-        } else {
+        if (taskInfo != null && taskInfo.topActivity != null) {
             mPackageName = taskInfo.topActivity.getPackageName();
             mPackageUid = getUid(mPackageName, taskInfo.userId);
+        } else {
+            mPackageName = null;
+            mPackageUid = INVALID_PACKAGE_UID;
         }
     }
 
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 4cd2c50..f1e06f7 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
@@ -26,11 +26,11 @@
 import android.animation.ValueAnimator;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.ActivityManager;
 import android.os.IBinder;
 import android.util.ArrayMap;
 import android.view.SurfaceControl;
 import android.window.TransitionInfo;
+import android.window.TransitionRequestInfo;
 import android.window.WindowContainerTransaction;
 
 import com.android.wm.shell.common.ShellExecutor;
@@ -99,8 +99,8 @@
 
     @Nullable
     @Override
-    public WindowContainerTransaction handleRequest(int type, @NonNull IBinder transition,
-            @Nullable ActivityManager.RunningTaskInfo triggerTask) {
+    public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
+            @NonNull TransitionRequestInfo request) {
         return null;
     }
 
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
new file mode 100644
index 0000000..cf141c6a
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.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 com.android.wm.shell.transition;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.Pair;
+import android.view.IRemoteAnimationFinishedCallback;
+import android.view.SurfaceControl;
+import android.window.IRemoteTransition;
+import android.window.TransitionFilter;
+import android.window.TransitionInfo;
+import android.window.TransitionRequestInfo;
+import android.window.WindowContainerTransaction;
+
+import com.android.wm.shell.common.ShellExecutor;
+
+import java.util.ArrayList;
+
+/**
+ * Handler that deals with RemoteTransitions. It will only request to handle a transition
+ * if the request includes a specific remote.
+ */
+public class RemoteTransitionHandler implements Transitions.TransitionHandler {
+    private final ShellExecutor mMainExecutor;
+
+    /** Includes remotes explicitly requested by, eg, ActivityOptions */
+    private final ArrayMap<IBinder, IRemoteTransition> mPendingRemotes = new ArrayMap<>();
+
+    /** Ordered by specificity. Last filters will be checked first */
+    private final ArrayList<Pair<TransitionFilter, IRemoteTransition>> mFilters =
+            new ArrayList<>();
+
+    RemoteTransitionHandler(@NonNull ShellExecutor mainExecutor) {
+        mMainExecutor = mainExecutor;
+    }
+
+    void addFiltered(TransitionFilter filter, IRemoteTransition remote) {
+        mFilters.add(new Pair<TransitionFilter, IRemoteTransition>(filter, remote));
+    }
+
+    void removeFiltered(IRemoteTransition remote) {
+        for (int i = mFilters.size() - 1; i >= 0; --i) {
+            if (mFilters.get(i).second == remote) {
+                mFilters.remove(i);
+            }
+        }
+    }
+
+    @Override
+    public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
+            @NonNull SurfaceControl.Transaction t, @NonNull Runnable finishCallback) {
+        IRemoteTransition pendingRemote = mPendingRemotes.remove(transition);
+        if (pendingRemote == null) {
+            // If no explicit remote, search filters until one matches
+            for (int i = mFilters.size() - 1; i >= 0; --i) {
+                if (mFilters.get(i).first.matches(info)) {
+                    pendingRemote = mFilters.get(i).second;
+                    break;
+                }
+            }
+        }
+
+        if (pendingRemote == null) return false;
+
+        final IRemoteTransition remote = pendingRemote;
+        final IBinder.DeathRecipient remoteDied = () -> {
+            Log.e(Transitions.TAG, "Remote transition died, finishing");
+            mMainExecutor.execute(finishCallback);
+        };
+        IRemoteAnimationFinishedCallback cb = new IRemoteAnimationFinishedCallback.Stub() {
+            @Override
+            public void onAnimationFinished() throws RemoteException {
+                if (remote.asBinder() != null) {
+                    remote.asBinder().unlinkToDeath(remoteDied, 0 /* flags */);
+                }
+                mMainExecutor.execute(finishCallback);
+            }
+        };
+        try {
+            if (remote.asBinder() != null) {
+                remote.asBinder().linkToDeath(remoteDied, 0 /* flags */);
+            }
+            remote.startAnimation(info, t, cb);
+        } catch (RemoteException e) {
+            Log.e(Transitions.TAG, "Error running remote transition.", e);
+            mMainExecutor.execute(finishCallback);
+        }
+        return true;
+    }
+
+    @Override
+    @Nullable
+    public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
+            @Nullable TransitionRequestInfo request) {
+        IRemoteTransition remote = request.getRemoteTransition();
+        if (remote == null) return null;
+        mPendingRemotes.put(transition, remote);
+        return new WindowContainerTransaction();
+    }
+}
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 3b2ac70..c085168 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
@@ -25,15 +25,18 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.ActivityManager;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.util.ArrayMap;
+import android.util.Log;
 import android.view.SurfaceControl;
 import android.view.WindowManager;
+import android.window.IRemoteTransition;
 import android.window.ITransitionPlayer;
+import android.window.TransitionFilter;
 import android.window.TransitionInfo;
+import android.window.TransitionRequestInfo;
 import android.window.WindowContainerTransaction;
 import android.window.WindowOrganizer;
 
@@ -44,6 +47,7 @@
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.common.annotations.ExternalThread;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 
 import java.util.ArrayList;
@@ -51,7 +55,7 @@
 
 /** Plays transition animations */
 public class Transitions {
-    private static final String TAG = "ShellTransitions";
+    static final String TAG = "ShellTransitions";
 
     /** Set to {@code true} to enable shell transitions. */
     public static final boolean ENABLE_SHELL_TRANSITIONS =
@@ -61,6 +65,7 @@
     private final ShellExecutor mMainExecutor;
     private final ShellExecutor mAnimExecutor;
     private final TransitionPlayerImpl mPlayerImpl;
+    private final RemoteTransitionHandler mRemoteTransitionHandler;
 
     /** List of possible handlers. Ordered by specificity (eg. tapped back to front). */
     private final ArrayList<TransitionHandler> mHandlers = new ArrayList<>();
@@ -80,10 +85,28 @@
         mPlayerImpl = new TransitionPlayerImpl();
         // The very last handler (0 in the list) should be the default one.
         mHandlers.add(new DefaultTransitionHandler(pool, mainExecutor, animExecutor));
+        // Next lowest priority is remote transitions.
+        mRemoteTransitionHandler = new RemoteTransitionHandler(mainExecutor);
+        mHandlers.add(mRemoteTransitionHandler);
+    }
+
+    private Transitions() {
+        mOrganizer = null;
+        mMainExecutor = null;
+        mAnimExecutor = null;
+        mPlayerImpl = null;
+        mRemoteTransitionHandler = null;
+    }
+
+    /** Create an empty/non-registering transitions object for system-ui tests. */
+    @VisibleForTesting
+    public static Transitions createEmptyForTesting() {
+        return new Transitions();
     }
 
     /** Register this transition handler with Core */
     public void register(ShellTaskOrganizer taskOrganizer) {
+        if (mPlayerImpl == null) return;
         taskOrganizer.registerTransitionPlayer(mPlayerImpl);
     }
 
@@ -109,6 +132,19 @@
         mHandlers.set(0, handler);
     }
 
+    /** Register a remote transition to be used when `filter` matches an incoming transition */
+    @ExternalThread
+    public void registerRemote(@NonNull TransitionFilter filter,
+            @NonNull IRemoteTransition remoteTransition) {
+        mMainExecutor.execute(() -> mRemoteTransitionHandler.addFiltered(filter, remoteTransition));
+    }
+
+    /** Unregisters a remote transition and all associated filters */
+    @ExternalThread
+    public void unregisterRemote(@NonNull IRemoteTransition remoteTransition) {
+        mMainExecutor.execute(() -> mRemoteTransitionHandler.removeFiltered(remoteTransition));
+    }
+
     /** @return true if the transition was triggered by opening something vs closing something */
     public static boolean isOpeningType(@WindowManager.TransitionType int type) {
         return type == TRANSIT_OPEN
@@ -126,6 +162,8 @@
         if (info.getRootLeash().isValid()) {
             t.show(info.getRootLeash());
         }
+        // Put animating stuff above this line and put static stuff below it.
+        int zSplitLine = info.getChanges().size();
         // changes should be ordered top-to-bottom in z
         for (int i = info.getChanges().size() - 1; i >= 0; --i) {
             final TransitionInfo.Change change = info.getChanges().get(i);
@@ -152,7 +190,7 @@
                 t.setMatrix(leash, 1, 0, 0, 1);
                 if (isOpening) {
                     // put on top with 0 alpha
-                    t.setLayer(leash, info.getChanges().size() - i);
+                    t.setLayer(leash, zSplitLine + info.getChanges().size() - i);
                     if ((change.getFlags() & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) {
                         // This received a transferred starting window, so make it immediately
                         // visible.
@@ -162,19 +200,19 @@
                     }
                 } else {
                     // put on bottom and leave it visible
-                    t.setLayer(leash, -i);
+                    t.setLayer(leash, zSplitLine - i);
                     t.setAlpha(leash, 1.f);
                 }
             } else if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) {
                 if (isOpening) {
                     // put on bottom and leave visible
-                    t.setLayer(leash, -i);
+                    t.setLayer(leash, zSplitLine - i);
                 } else {
                     // put on top
-                    t.setLayer(leash, info.getChanges().size() - i);
+                    t.setLayer(leash, zSplitLine + info.getChanges().size() - i);
                 }
             } else { // CHANGE
-                t.setLayer(leash, info.getChanges().size() - i);
+                t.setLayer(leash, zSplitLine + info.getChanges().size() - i);
             }
         }
     }
@@ -219,7 +257,8 @@
 
     private void onFinish(IBinder transition) {
         if (!mActiveTransitions.containsKey(transition)) {
-            throw new IllegalStateException("Trying to finish an already-finished transition.");
+            Log.e(TAG, "Trying to finish a non-running transition. Maybe remote crashed?");
+            return;
         }
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
                 "Transition animations finished, notifying core %s", transition);
@@ -227,24 +266,24 @@
         mOrganizer.finishTransition(transition, null, null);
     }
 
-    void requestStartTransition(int type, @NonNull IBinder transitionToken,
-            @Nullable ActivityManager.RunningTaskInfo triggerTask) {
-        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Transition requested: type=%d %s",
-                type, transitionToken);
-
+    void requestStartTransition(@NonNull IBinder transitionToken,
+            @Nullable TransitionRequestInfo request) {
+        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Transition requested: %s %s",
+                transitionToken, request);
         if (mActiveTransitions.containsKey(transitionToken)) {
             throw new RuntimeException("Transition already started " + transitionToken);
         }
         final ActiveTransition active = new ActiveTransition();
         WindowContainerTransaction wct = null;
         for (int i = mHandlers.size() - 1; i >= 0; --i) {
-            wct = mHandlers.get(i).handleRequest(type, transitionToken, triggerTask);
+            wct = mHandlers.get(i).handleRequest(transitionToken, request);
             if (wct != null) {
                 active.mFirstHandler = mHandlers.get(i);
                 break;
             }
         }
-        IBinder transition = mOrganizer.startTransition(type, transitionToken, wct);
+        IBinder transition = mOrganizer.startTransition(
+                request.getType(), transitionToken, wct);
         mActiveTransitions.put(transition, active);
     }
 
@@ -267,6 +306,7 @@
          * for a particular transition. Otherwise, it is only called if no other handler before
          * it handled the transition.
          *
+         * @param finishCallback Call this when finished. This MUST be called on main thread.
          * @return true if transition was handled, false if not (falls-back to default).
          */
         boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@@ -274,15 +314,15 @@
 
         /**
          * Potentially handles a startTransition request.
-         * @param type The transition type
-         * @param triggerTask The task which triggered this transition request.
-         * @return WCT to apply with transition-start or null if this handler isn't handling
-         *         the request.
+         *
+         * @param transition The transition whose start is being requested.
+         * @param request Information about what is requested.
+         * @return WCT to apply with transition-start or null. If a WCT is returned here, this
+         *         handler will be the first in line to animate.
          */
         @Nullable
-        WindowContainerTransaction handleRequest(@WindowManager.TransitionType int type,
-                @NonNull IBinder transition,
-                @Nullable ActivityManager.RunningTaskInfo triggerTask);
+        WindowContainerTransaction handleRequest(@NonNull IBinder transition,
+                @NonNull TransitionRequestInfo request);
     }
 
     @BinderThread
@@ -296,11 +336,9 @@
         }
 
         @Override
-        public void requestStartTransition(int i, IBinder iBinder,
-                ActivityManager.RunningTaskInfo runningTaskInfo) throws RemoteException {
-            mMainExecutor.execute(() -> {
-                Transitions.this.requestStartTransition(i, iBinder, runningTaskInfo);
-            });
+        public void requestStartTransition(IBinder iBinder,
+                TransitionRequestInfo request) throws RemoteException {
+            mMainExecutor.execute(() -> Transitions.this.requestStartTransition(iBinder, request));
         }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterLegacySplitScreenTest.kt
index 85bf4a1..05e4539 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterLegacySplitScreenTest.kt
@@ -155,7 +155,9 @@
                         showsAppWindow(splitScreenApp.defaultWindowName)
                                 .and().showsAppWindow(secondaryApp.defaultWindowName)
                     }
-                    visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(LAUNCHER_PACKAGE_NAME))
+                    visibleWindowsShownMoreThanOneConsecutiveEntry(
+                            listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName,
+                                    secondaryApp.defaultWindowName))
                 }
             }
         }
@@ -187,7 +189,8 @@
                     end {
                         hidesAppWindow(nonResizeableApp.defaultWindowName)
                     }
-                    visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(LAUNCHER_PACKAGE_NAME))
+                    visibleWindowsShownMoreThanOneConsecutiveEntry(
+                            listOf(LAUNCHER_PACKAGE_NAME, nonResizeableApp.defaultWindowName))
                 }
             }
         }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottomTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottomTest.kt
index 9586fd1..bdc429c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottomTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottomTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
+import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.RequiresDevice
 import androidx.test.platform.app.InstrumentationRegistry
@@ -45,6 +46,7 @@
  * Test open app to split screen.
  * To run this test: `atest WMShellFlickerTests:ExitLegacySplitScreenFromBottomTest`
  */
+@Presubmit
 @RequiresDevice
 @RunWith(Parameterized::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreenTest.kt
index e9d3eb7..26fabbd 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreenTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
+import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.dsl.runWithFlicker
@@ -34,6 +35,7 @@
  * Test open app to split screen.
  * To run this test: `atest WMShellFlickerTests:NonResizableDismissInLegacySplitScreenTest`
  */
+@Presubmit
 @RequiresDevice
 @RunWith(Parameterized::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
@@ -64,7 +66,8 @@
                     }
                     visibleLayersShownMoreThanOneConsecutiveEntry(
                             listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName,
-                                    nonResizeableApp.defaultWindowName, LETTER_BOX_NAME)
+                                    nonResizeableApp.defaultWindowName, LETTER_BOX_NAME,
+                                    TOAST_NAME, LIVE_WALLPAPER_PACKAGE_NAME)
                     )
                 }
                 windowManagerTrace {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreenTest.kt
index b5a36f5..e2439f2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreenTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
+import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.dsl.runWithFlicker
@@ -34,6 +35,7 @@
  * Test open app to split screen.
  * To run this test: `atest WMShellFlickerTests:NonResizableLaunchInLegacySplitScreenTest`
  */
+@Presubmit
 @RequiresDevice
 @RunWith(Parameterized::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
@@ -44,7 +46,7 @@
 
     @Test
     fun testNonResizableLaunchInLegacySplitScreenTest() {
-        val testTag = "NonResizableLaunchInLegacySplitScreenTest"
+        val testTag = "testNonResizableLaunchInLegacySplitScreenTest"
 
         runWithFlicker(transitionSetup) {
             withTestName { testTag }
@@ -64,7 +66,8 @@
                     }
                     visibleLayersShownMoreThanOneConsecutiveEntry(
                             listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName,
-                                    nonResizeableApp.defaultWindowName, LETTER_BOX_NAME)
+                                    nonResizeableApp.defaultWindowName, LETTER_BOX_NAME,
+                                    TOAST_NAME, LIVE_WALLPAPER_PACKAGE_NAME)
                     )
                 }
                 windowManagerTrace {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreenTest.kt
index 90577ef..d004c06 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreenTest.kt
@@ -29,6 +29,7 @@
 import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
 import com.android.server.wm.flicker.noUncoveredRegions
 import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import com.android.wm.shell.flicker.appPairsDividerBecomesVisible
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
 import org.junit.FixMethodOrder
@@ -41,8 +42,7 @@
  * Test open app to split screen.
  * To run this test: `atest WMShellFlickerTests:OpenAppToLegacySplitScreenTest`
  */
-// TODO: Add back to pre-submit when stable.
-//@Presubmit
+@Presubmit
 @RequiresDevice
 @RunWith(Parameterized::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
@@ -53,28 +53,37 @@
     @Test
     fun OpenAppToLegacySplitScreenTest() {
         val testTag = "OpenAppToLegacySplitScreenTest"
-
+        val helper = WindowManagerStateHelper()
         runWithFlicker(transitionSetup) {
             withTestName { testTag }
             repeat { SplitScreenHelper.TEST_REPETITIONS }
+            setup {
+                eachRun {
+                    splitScreenApp.launchViaIntent()
+                    device.pressHome()
+                    this.setRotation(rotation)
+                }
+            }
             transitions {
-                splitScreenApp.launchViaIntent()
-                device.pressHome()
-                this.setRotation(rotation)
                 device.launchSplitScreen()
+                helper.waitForAppTransitionIdle()
             }
             assertions {
                 windowManagerTrace {
-                    visibleWindowsShownMoreThanOneConsecutiveEntry()
+                    visibleWindowsShownMoreThanOneConsecutiveEntry(
+                            listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName,
+                                    LETTER_BOX_NAME)
+                    )
                     appWindowBecomesVisible(splitScreenApp.getPackage())
                 }
 
                 layersTrace {
-                    navBarLayerIsAlwaysVisible(bugId = 140855415)
+                    navBarLayerIsAlwaysVisible()
                     noUncoveredRegions(rotation, enabled = false)
-                    statusBarLayerIsAlwaysVisible(bugId = 140855415)
+                    statusBarLayerIsAlwaysVisible()
                     visibleLayersShownMoreThanOneConsecutiveEntry(
-                            listOf(LAUNCHER_PACKAGE_NAME))
+                            listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName,
+                                    LETTER_BOX_NAME))
                     appPairsDividerBecomesVisible()
                     layerBecomesVisible(splitScreenApp.getPackage())
                 }
@@ -92,7 +101,8 @@
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
         fun getParams(): Collection<Array<Any>> {
-            val supportedRotations = intArrayOf(Surface.ROTATION_0, Surface.ROTATION_90)
+            // TODO(b/161435597) causes the test not to work on 90 degrees
+            val supportedRotations = intArrayOf(Surface.ROTATION_0)
             return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
         }
     }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreenTest.kt
index 391cb2a..8ee9263 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreenTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
+import android.platform.test.annotations.Presubmit
 import android.graphics.Region
 import android.util.Rational
 import android.view.Surface
@@ -61,6 +62,7 @@
  *
  * Currently it runs only in 0 degrees because of b/156100803
  */
+@Presubmit
 @RequiresDevice
 @RunWith(Parameterized::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppTest.kt
index 923f2a4..594b4c1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
+import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.dsl.FlickerBuilder
@@ -42,6 +43,7 @@
  * Test open app to split screen.
  * To run this test: `atest WMShellFlickerTests:RotateOneLaunchedAppTest`
  */
+@Presubmit
 @RequiresDevice
 @RunWith(Parameterized::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppTest.kt
index 4578f68..6ee0491 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
+import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.dsl.FlickerBuilder
@@ -43,6 +44,7 @@
  * Test open app to split screen.
  * To run this test: `atest WMShellFlickerTests:RotateTwoLaunchedAppTest`
  */
+@Presubmit
 @RequiresDevice
 @RunWith(Parameterized::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/SplitScreenTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/SplitScreenTestBase.kt
index 2b94c5f..8c90124 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/SplitScreenTestBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/SplitScreenTestBase.kt
@@ -52,6 +52,7 @@
     protected val LIVE_WALLPAPER_PACKAGE_NAME =
             "com.breel.wallpapers18.soundviz.wallpaper.variations.SoundVizWallpaperV2"
     protected val LETTER_BOX_NAME = "Letterbox"
+    protected val TOAST_NAME = "Toast"
 
     protected val transitionSetup: FlickerBuilder
         get() = FlickerBuilder(instrumentation).apply {
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 16d13f4..f141167 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
@@ -28,7 +28,6 @@
 import android.os.Handler;
 import android.provider.Settings;
 import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
 import android.view.Display;
 
 import androidx.test.filters.SmallTest;
@@ -67,6 +66,8 @@
     @Mock
     OneHandedTimeoutHandler mMockTimeoutHandler;
     @Mock
+    OneHandedUiEventLogger mMockUiEventLogger;
+    @Mock
     IOverlayManager mMockOverlayManager;
     @Mock
     TaskStackListenerImpl mMockTaskStackListener;
@@ -89,6 +90,7 @@
                 mMockTutorialHandler,
                 mMockGestureHandler,
                 mTimeoutHandler,
+                mMockUiEventLogger,
                 mMockOverlayManager,
                 mMockTaskStackListener,
                 mMockShellMainExecutor,
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 c451b8b2..c3e6bf3 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
@@ -21,7 +21,6 @@
 import android.content.om.IOverlayManager;
 import android.os.Handler;
 import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
 
 import androidx.test.filters.SmallTest;
 
@@ -58,6 +57,9 @@
     ShellExecutor mMockShellMainExecutor;
     @Mock
     Handler mMockShellMainHandler;
+    @Mock
+    OneHandedUiEventLogger mMockUiEventLogger;
+
 
     @Before
     public void setUp() {
@@ -75,6 +77,7 @@
                 mTutorialHandler,
                 mGestureHandler,
                 mTimeoutHandler,
+                mMockUiEventLogger,
                 mMockOverlayManager,
                 mMockTaskStackListener,
                 mMockShellMainExecutor,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedEventsTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedUiEventLoggerTest.java
similarity index 67%
rename from libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedEventsTest.java
rename to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedUiEventLoggerTest.java
index 492c34e..e29fc6a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedEventsTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedUiEventLoggerTest.java
@@ -33,7 +33,7 @@
 
 @RunWith(Parameterized.class)
 @SmallTest
-public class OneHandedEventsTest extends OneHandedTestCase {
+public class OneHandedUiEventLoggerTest extends OneHandedTestCase {
 
     private UiEventLoggerFake mUiEventLogger;
 
@@ -48,7 +48,6 @@
     @Before
     public void setFakeLoggers() {
         mUiEventLogger = new UiEventLoggerFake();
-        OneHandedEvents.sUiEventLogger = mUiEventLogger;
     }
 
     @Test
@@ -63,42 +62,42 @@
     public static Collection<Object[]> data() {
         return Arrays.asList(new Object[][]{
                 // Triggers
-                {OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_GESTURE_IN,
+                {OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_GESTURE_IN,
                         "writeEvent one_handed_trigger_gesture_in"},
-                {OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_GESTURE_OUT,
+                {OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_GESTURE_OUT,
                         "writeEvent one_handed_trigger_gesture_out"},
-                {OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_OVERSPACE_OUT,
+                {OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_OVERSPACE_OUT,
                         "writeEvent one_handed_trigger_overspace_out"},
-                {OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_POP_IME_OUT,
+                {OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_POP_IME_OUT,
                         "writeEvent one_handed_trigger_pop_ime_out"},
-                {OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_ROTATION_OUT,
+                {OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_ROTATION_OUT,
                         "writeEvent one_handed_trigger_rotation_out"},
-                {OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT,
+                {OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT,
                         "writeEvent one_handed_trigger_app_taps_out"},
-                {OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_TIMEOUT_OUT,
+                {OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_TIMEOUT_OUT,
                         "writeEvent one_handed_trigger_timeout_out"},
-                {OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_SCREEN_OFF_OUT,
+                {OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_SCREEN_OFF_OUT,
                         "writeEvent one_handed_trigger_screen_off_out"},
                 // Settings toggles
-                {OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_ENABLED_ON,
+                {OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_ENABLED_ON,
                         "writeEvent one_handed_settings_enabled_on"},
-                {OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_ENABLED_OFF,
+                {OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_ENABLED_OFF,
                         "writeEvent one_handed_settings_enabled_off"},
-                {OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_APP_TAPS_EXIT_ON,
+                {OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_APP_TAPS_EXIT_ON,
                         "writeEvent one_handed_settings_app_taps_exit_on"},
-                {OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_APP_TAPS_EXIT_OFF,
+                {OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_APP_TAPS_EXIT_OFF,
                         "writeEvent one_handed_settings_app_taps_exit_off"},
-                {OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_EXIT_ON,
+                {OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_EXIT_ON,
                         "writeEvent one_handed_settings_timeout_exit_on"},
-                {OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_EXIT_OFF,
+                {OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_EXIT_OFF,
                         "writeEvent one_handed_settings_timeout_exit_off"},
-                {OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_NEVER,
+                {OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_NEVER,
                         "writeEvent one_handed_settings_timeout_seconds_never"},
-                {OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_4,
+                {OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_4,
                         "writeEvent one_handed_settings_timeout_seconds_4"},
-                {OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_8,
+                {OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_8,
                         "writeEvent one_handed_settings_timeout_seconds_8"},
-                {OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_12,
+                {OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_12,
                         "writeEvent one_handed_settings_timeout_seconds_12"}
         });
     }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index c46e59a..f3bee4b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -16,15 +16,21 @@
 
 package com.android.wm.shell.transition;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_OPEN;
+import static android.view.WindowManager.TRANSIT_TO_BACK;
+import static android.view.WindowManager.TRANSIT_TO_FRONT;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 
 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.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
@@ -37,9 +43,14 @@
 import android.app.ActivityManager.RunningTaskInfo;
 import android.os.Binder;
 import android.os.IBinder;
+import android.os.RemoteException;
+import android.view.IRemoteAnimationFinishedCallback;
 import android.view.SurfaceControl;
 import android.view.WindowManager;
+import android.window.IRemoteTransition;
+import android.window.TransitionFilter;
 import android.window.TransitionInfo;
+import android.window.TransitionRequestInfo;
 import android.window.WindowContainerTransaction;
 import android.window.WindowOrganizer;
 
@@ -84,7 +95,8 @@
         transitions.replaceDefaultHandlerForTest(mDefaultHandler);
 
         IBinder transitToken = new Binder();
-        transitions.requestStartTransition(TRANSIT_OPEN, transitToken, null /* trigger */);
+        transitions.requestStartTransition(transitToken,
+                new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
         verify(mOrganizer, times(1)).startTransition(eq(TRANSIT_OPEN), eq(transitToken), any());
         TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN)
                 .addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
@@ -118,10 +130,10 @@
 
             @Nullable
             @Override
-            public WindowContainerTransaction handleRequest(int type, @NonNull IBinder transition,
-                    @Nullable RunningTaskInfo triggerTask) {
-                return (triggerTask != null
-                        && triggerTask.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW)
+            public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
+                    @NonNull TransitionRequestInfo request) {
+                final RunningTaskInfo task = request.getTriggerTask();
+                return (task != null && task.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW)
                         ? handlerWCT : null;
             }
         };
@@ -132,7 +144,8 @@
                 .addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
 
         // Make a request that will be rejected by the testhandler.
-        transitions.requestStartTransition(TRANSIT_OPEN, transitToken, null /* trigger */);
+        transitions.requestStartTransition(transitToken,
+                new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
         verify(mOrganizer, times(1)).startTransition(eq(TRANSIT_OPEN), eq(transitToken), isNull());
         transitions.onTransitionReady(transitToken, open, mock(SurfaceControl.Transaction.class));
         assertEquals(1, mDefaultHandler.activeCount());
@@ -143,7 +156,8 @@
         // Make a request that will be handled by testhandler but not animated by it.
         RunningTaskInfo mwTaskInfo =
                 createTaskInfo(1, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
-        transitions.requestStartTransition(TRANSIT_OPEN, transitToken, mwTaskInfo);
+        transitions.requestStartTransition(transitToken,
+                new TransitionRequestInfo(TRANSIT_OPEN, mwTaskInfo, null /* remote */));
         verify(mOrganizer, times(1)).startTransition(
                 eq(TRANSIT_OPEN), eq(transitToken), eq(handlerWCT));
         transitions.onTransitionReady(transitToken, open, mock(SurfaceControl.Transaction.class));
@@ -157,9 +171,10 @@
         // the test handler gets first shot at animating since it claimed to handle it.
         TestTransitionHandler topHandler = new TestTransitionHandler();
         transitions.addHandler(topHandler);
-        transitions.requestStartTransition(TRANSIT_CHANGE, transitToken, mwTaskInfo);
+        transitions.requestStartTransition(transitToken,
+                new TransitionRequestInfo(TRANSIT_CHANGE, mwTaskInfo, null /* remote */));
         verify(mOrganizer, times(1)).startTransition(
-                eq(TRANSIT_OPEN), eq(transitToken), eq(handlerWCT));
+                eq(TRANSIT_CHANGE), eq(transitToken), eq(handlerWCT));
         TransitionInfo change = new TransitionInfoBuilder(TRANSIT_CHANGE)
                 .addChange(TRANSIT_CHANGE).build();
         transitions.onTransitionReady(transitToken, change, mock(SurfaceControl.Transaction.class));
@@ -170,6 +185,110 @@
         mMainExecutor.flushAll();
     }
 
+    @Test
+    public void testRequestRemoteTransition() {
+        Transitions transitions = new Transitions(mOrganizer, mTransactionPool, mMainExecutor,
+                mAnimExecutor);
+        transitions.replaceDefaultHandlerForTest(mDefaultHandler);
+
+        final boolean[] remoteCalled = new boolean[]{false};
+        IRemoteTransition testRemote = new IRemoteTransition.Stub() {
+            @Override
+            public void startAnimation(TransitionInfo info, SurfaceControl.Transaction t,
+                    IRemoteAnimationFinishedCallback finishCallback) throws RemoteException {
+                remoteCalled[0] = true;
+                finishCallback.onAnimationFinished();
+            }
+        };
+        IBinder transitToken = new Binder();
+        transitions.requestStartTransition(transitToken,
+                new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, testRemote));
+        verify(mOrganizer, times(1)).startTransition(eq(TRANSIT_OPEN), eq(transitToken), any());
+        TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN)
+                .addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
+        transitions.onTransitionReady(transitToken, info, mock(SurfaceControl.Transaction.class));
+        assertEquals(0, mDefaultHandler.activeCount());
+        assertTrue(remoteCalled[0]);
+        mDefaultHandler.finishAll();
+        mMainExecutor.flushAll();
+        verify(mOrganizer, times(1)).finishTransition(eq(transitToken), any(), any());
+    }
+
+    @Test
+    public void testTransitionFilterActivityType() {
+        TransitionFilter filter = new TransitionFilter();
+        filter.mRequirements =
+                new TransitionFilter.Requirement[]{new TransitionFilter.Requirement()};
+        filter.mRequirements[0].mActivityType = ACTIVITY_TYPE_HOME;
+        filter.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT};
+
+        final TransitionInfo openHome = new TransitionInfoBuilder(TRANSIT_OPEN)
+                .addChange(TRANSIT_OPEN,
+                        createTaskInfo(1, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME)).build();
+        assertTrue(filter.matches(openHome));
+
+        final TransitionInfo openStd = new TransitionInfoBuilder(TRANSIT_OPEN)
+                .addChange(TRANSIT_OPEN, createTaskInfo(
+                        1, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD)).build();
+        assertFalse(filter.matches(openStd));
+    }
+
+    @Test
+    public void testTransitionFilterMultiRequirement() {
+        // filter that requires at-least one opening and one closing app
+        TransitionFilter filter = new TransitionFilter();
+        filter.mRequirements = new TransitionFilter.Requirement[]{
+                new TransitionFilter.Requirement(), new TransitionFilter.Requirement()};
+        filter.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT};
+        filter.mRequirements[1].mModes = new int[]{TRANSIT_CLOSE, TRANSIT_TO_BACK};
+
+        final TransitionInfo openOnly = new TransitionInfoBuilder(TRANSIT_OPEN)
+                .addChange(TRANSIT_OPEN).build();
+        assertFalse(filter.matches(openOnly));
+
+        final TransitionInfo openClose = new TransitionInfoBuilder(TRANSIT_OPEN)
+                .addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
+        assertTrue(filter.matches(openClose));
+    }
+
+    @Test
+    public void testRegisteredRemoteTransition() {
+        Transitions transitions = new Transitions(mOrganizer, mTransactionPool, mMainExecutor,
+                mAnimExecutor);
+        transitions.replaceDefaultHandlerForTest(mDefaultHandler);
+
+        final boolean[] remoteCalled = new boolean[]{false};
+        IRemoteTransition testRemote = new IRemoteTransition.Stub() {
+            @Override
+            public void startAnimation(TransitionInfo info, SurfaceControl.Transaction t,
+                    IRemoteAnimationFinishedCallback finishCallback) throws RemoteException {
+                remoteCalled[0] = true;
+                finishCallback.onAnimationFinished();
+            }
+        };
+
+        TransitionFilter filter = new TransitionFilter();
+        filter.mRequirements =
+                new TransitionFilter.Requirement[]{new TransitionFilter.Requirement()};
+        filter.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT};
+
+        transitions.registerRemote(filter, testRemote);
+        mMainExecutor.flushAll();
+
+        IBinder transitToken = new Binder();
+        transitions.requestStartTransition(transitToken,
+                new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
+        verify(mOrganizer, times(1)).startTransition(eq(TRANSIT_OPEN), eq(transitToken), any());
+        TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN)
+                .addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
+        transitions.onTransitionReady(transitToken, info, mock(SurfaceControl.Transaction.class));
+        assertEquals(0, mDefaultHandler.activeCount());
+        assertTrue(remoteCalled[0]);
+        mDefaultHandler.finishAll();
+        mMainExecutor.flushAll();
+        verify(mOrganizer, times(1)).finishTransition(eq(transitToken), any(), any());
+    }
+
     class TransitionInfoBuilder {
         final TransitionInfo mInfo;
 
@@ -209,8 +328,8 @@
 
         @Nullable
         @Override
-        public WindowContainerTransaction handleRequest(int type, @NonNull IBinder transition,
-                @Nullable RunningTaskInfo triggerTask) {
+        public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
+                @NonNull TransitionRequestInfo request) {
             return null;
         }
 
@@ -240,4 +359,10 @@
         return taskInfo;
     }
 
+    private static RunningTaskInfo createTaskInfo(int taskId) {
+        RunningTaskInfo taskInfo = new RunningTaskInfo();
+        taskInfo.taskId = taskId;
+        return taskInfo;
+    }
+
 }
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 6bf2e99..11a9086 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -16,12 +16,14 @@
 
 #include "RecordingCanvas.h"
 
-#include "pipeline/skia/FunctorDrawable.h"
-#include "VectorDrawable.h"
+#include <GrRecordingContext.h>
+
+#include <experimental/type_traits>
 
 #include "SkAndroidFrameworkUtils.h"
 #include "SkCanvas.h"
 #include "SkCanvasPriv.h"
+#include "SkColor.h"
 #include "SkData.h"
 #include "SkDrawShadowInfo.h"
 #include "SkImage.h"
@@ -33,8 +35,8 @@
 #include "SkRegion.h"
 #include "SkTextBlob.h"
 #include "SkVertices.h"
-
-#include <experimental/type_traits>
+#include "VectorDrawable.h"
+#include "pipeline/skia/FunctorDrawable.h"
 
 namespace android {
 namespace uirenderer {
@@ -500,7 +502,68 @@
     // SkDrawable::onSnapGpuDrawHandler callback instead of SkDrawable::onDraw.
     // SkCanvas::drawDrawable/SkGpuDevice::drawDrawable has the logic to invoke
     // onSnapGpuDrawHandler.
-    void draw(SkCanvas* c, const SkMatrix&) const { c->drawDrawable(drawable.get()); }
+private:
+    // Unfortunately WebView does not have complex clip information serialized, and we only perform
+    // best-effort stencil fill for GLES. So for Vulkan we create an intermediate layer if the
+    // canvas clip is complex.
+    static bool needsCompositedLayer(SkCanvas* c) {
+        if (Properties::getRenderPipelineType() != RenderPipelineType::SkiaVulkan) {
+            return false;
+        }
+        SkRegion clipRegion;
+        // WebView's rasterizer has access to simple clips, so for Vulkan we only need to check if
+        // the clip is more complex than a rectangle.
+        c->temporary_internal_getRgnClip(&clipRegion);
+        return clipRegion.isComplex();
+    }
+
+    mutable SkImageInfo mLayerImageInfo;
+    mutable sk_sp<SkSurface> mLayerSurface = nullptr;
+
+public:
+    void draw(SkCanvas* c, const SkMatrix&) const {
+        if (needsCompositedLayer(c)) {
+            // What we do now is create an offscreen surface, sized by the clip bounds.
+            // We won't apply a clip while drawing - clipping will be performed when compositing the
+            // surface back onto the original canvas. Note also that we're not using saveLayer
+            // because the webview functor still doesn't respect the canvas clip stack.
+            const SkIRect deviceBounds = c->getDeviceClipBounds();
+            if (mLayerSurface == nullptr || c->imageInfo() != mLayerImageInfo) {
+                GrRecordingContext* directContext = c->recordingContext();
+                mLayerImageInfo =
+                        c->imageInfo().makeWH(deviceBounds.width(), deviceBounds.height());
+                mLayerSurface = SkSurface::MakeRenderTarget(directContext, SkBudgeted::kYes,
+                                                            mLayerImageInfo, 0,
+                                                            kTopLeft_GrSurfaceOrigin, nullptr);
+            }
+
+            SkCanvas* layerCanvas = mLayerSurface->getCanvas();
+
+            SkAutoCanvasRestore(layerCanvas, true);
+            layerCanvas->clear(SK_ColorTRANSPARENT);
+
+            // Preserve the transform from the original canvas, but now the clip rectangle is
+            // anchored at the origin so we need to transform the clipped content to the origin.
+            SkM44 mat4(c->getLocalToDevice());
+            mat4.postTranslate(-deviceBounds.fLeft, -deviceBounds.fTop);
+            layerCanvas->concat(mat4);
+            layerCanvas->drawDrawable(drawable.get());
+
+            SkAutoCanvasRestore acr(c, true);
+
+            // Temporarily use an identity transform, because this is just blitting to the parent
+            // canvas with an offset.
+            SkMatrix invertedMatrix;
+            if (!c->getTotalMatrix().invert(&invertedMatrix)) {
+                ALOGW("Unable to extract invert canvas matrix; aborting VkFunctor draw");
+                return;
+            }
+            c->concat(invertedMatrix);
+            mLayerSurface->draw(c, deviceBounds.fLeft, deviceBounds.fTop, nullptr);
+        } else {
+            c->drawDrawable(drawable.get());
+        }
+    }
 };
 }
 
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 815ffde..1ebc489 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -819,10 +819,10 @@
                             uirenderer::CanvasPropertyPrimitive* radius,
                             uirenderer::CanvasPropertyPaint* paint,
                             uirenderer::CanvasPropertyPrimitive* progress,
-                            sk_sp<SkRuntimeEffect> runtimeEffect) {
+                            const SkRuntimeShaderBuilder& effectBuilder) {
     sk_sp<uirenderer::skiapipeline::AnimatedRipple> drawable(
             new uirenderer::skiapipeline::AnimatedRipple(x, y, radius, paint, progress,
-                                                         runtimeEffect));
+                                                         effectBuilder));
     mCanvas->drawDrawable(drawable.get());
 }
 
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index b9370e9..155f6df 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -151,7 +151,7 @@
                             uirenderer::CanvasPropertyPrimitive* radius,
                             uirenderer::CanvasPropertyPaint* paint,
                             uirenderer::CanvasPropertyPrimitive* progress,
-                            sk_sp<SkRuntimeEffect> runtimeEffect) override;
+                            const SkRuntimeShaderBuilder& effectBuilder) override;
 
     virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) override;
     virtual void drawRenderNode(uirenderer::RenderNode* renderNode) override;
diff --git a/libs/hwui/canvas/CanvasOps.h b/libs/hwui/canvas/CanvasOps.h
index ea9fea97..fa0c45b 100644
--- a/libs/hwui/canvas/CanvasOps.h
+++ b/libs/hwui/canvas/CanvasOps.h
@@ -161,7 +161,7 @@
         }
 
         SkRuntimeShaderBuilder::BuilderUniform radiusU =
-                runtimeEffectBuilder.uniform("in_maxRadius");
+                runtimeEffectBuilder.uniform("in_radius");
         if (radiusU.fVar != nullptr) {
             radiusU = radius->value;
         }
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index 19ef7e3..fdfa288 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -30,7 +30,7 @@
 
 class SkAnimatedImage;
 class SkCanvasState;
-class SkRuntimeEffect;
+class SkRuntimeShaderBuilder;
 class SkVertices;
 
 namespace minikin {
@@ -138,7 +138,7 @@
                             uirenderer::CanvasPropertyPrimitive* radius,
                             uirenderer::CanvasPropertyPaint* paint,
                             uirenderer::CanvasPropertyPrimitive* progress,
-                            sk_sp<SkRuntimeEffect> runtimeEffect) = 0;
+                            const SkRuntimeShaderBuilder& effectBuilder) = 0;
 
     virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) = 0;
     virtual void drawRenderNode(uirenderer::RenderNode* renderNode) = 0;
diff --git a/libs/hwui/hwui/ImageDecoder.cpp b/libs/hwui/hwui/ImageDecoder.cpp
index 764bc4c..f055c6e 100644
--- a/libs/hwui/hwui/ImageDecoder.cpp
+++ b/libs/hwui/hwui/ImageDecoder.cpp
@@ -76,6 +76,11 @@
           || (!swapWidthHeight && decodeSize != targetSize);
 }
 
+SkISize ImageDecoder::getSampledDimensions(int sampleSize) const {
+    auto size = mCodec->getSampledDimensions(sampleSize);
+    return swapWidthHeight() ? swapped(size) : size;
+}
+
 bool ImageDecoder::setTargetSize(int width, int height) {
     if (width <= 0 || height <= 0) {
         return false;
diff --git a/libs/hwui/hwui/ImageDecoder.h b/libs/hwui/hwui/ImageDecoder.h
index 1b309bc..cbfffd5 100644
--- a/libs/hwui/hwui/ImageDecoder.h
+++ b/libs/hwui/hwui/ImageDecoder.h
@@ -38,6 +38,7 @@
                  sk_sp<SkPngChunkReader> peeker = nullptr);
     ~ImageDecoder();
 
+    SkISize getSampledDimensions(int sampleSize) const;
     bool setTargetSize(int width, int height);
     bool setCropRect(const SkIRect*);
 
diff --git a/libs/hwui/jni/ImageDecoder.cpp b/libs/hwui/jni/ImageDecoder.cpp
index 96e912f..ad7741b 100644
--- a/libs/hwui/jni/ImageDecoder.cpp
+++ b/libs/hwui/jni/ImageDecoder.cpp
@@ -465,7 +465,7 @@
 static jobject ImageDecoder_nGetSampledSize(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
                                             jint sampleSize) {
     auto* decoder = reinterpret_cast<ImageDecoder*>(nativePtr);
-    SkISize size = decoder->mCodec->getSampledDimensions(sampleSize);
+    SkISize size = decoder->getSampledDimensions(sampleSize);
     return env->NewObject(gSize_class, gSize_constructorMethodID, size.width(), size.height());
 }
 
diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp
index aaec60b..1dc5cd9 100644
--- a/libs/hwui/jni/Shader.cpp
+++ b/libs/hwui/jni/Shader.cpp
@@ -1,3 +1,6 @@
+#undef LOG_TAG
+#define LOG_TAG "ShaderJNI"
+
 #include "GraphicsJNI.h"
 #include "SkColorFilter.h"
 #include "SkGradientShader.h"
@@ -232,53 +235,73 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
-static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderFactory, jlong matrixPtr,
-        jbyteArray inputs, jlongArray inputShaders, jlong colorSpaceHandle, jboolean isOpaque) {
-    SkRuntimeEffect* effect = reinterpret_cast<SkRuntimeEffect*>(shaderFactory);
-    AutoJavaByteArray arInputs(env, inputs);
-
-    std::vector<sk_sp<SkShader>> shaderVector;
-    if (inputShaders) {
-        jsize shaderCount = env->GetArrayLength(inputShaders);
-        shaderVector.resize(shaderCount);
-        jlong* arrayPtr = env->GetLongArrayElements(inputShaders, NULL);
-        for (int i = 0; i < shaderCount; i++) {
-            shaderVector[i] = sk_ref_sp(reinterpret_cast<SkShader*>(arrayPtr[i]));
-        }
-        env->ReleaseLongArrayElements(inputShaders, arrayPtr, 0);
-    }
-
-    sk_sp<SkData> fData;
-    fData = SkData::MakeWithCopy(arInputs.ptr(), arInputs.length());
-    const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
-    sk_sp<SkShader> shader = effect->makeShader(fData, shaderVector.data(), shaderVector.size(),
-                                                matrix, isOpaque == JNI_TRUE);
-    ThrowIAE_IfNull(env, shader);
-
-    return reinterpret_cast<jlong>(shader.release());
-}
-
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
-static jlong RuntimeShader_createShaderFactory(JNIEnv* env, jobject, jstring sksl) {
+static jlong RuntimeShader_createShaderBuilder(JNIEnv* env, jobject, jstring sksl) {
     ScopedUtfChars strSksl(env, sksl);
     auto result = SkRuntimeEffect::Make(SkString(strSksl.c_str()));
     sk_sp<SkRuntimeEffect> effect = std::get<0>(result);
-    if (!effect) {
+    if (effect.get() == nullptr) {
         const auto& err = std::get<1>(result);
         doThrowIAE(env, err.c_str());
+        return 0;
     }
-    return reinterpret_cast<jlong>(effect.release());
+    return reinterpret_cast<jlong>(new SkRuntimeShaderBuilder(std::move(effect)));
 }
 
-///////////////////////////////////////////////////////////////////////////////////////////////
-
-static void Effect_safeUnref(SkRuntimeEffect* effect) {
-    SkSafeUnref(effect);
+static void SkRuntimeShaderBuilder_delete(SkRuntimeShaderBuilder* builder) {
+    delete builder;
 }
 
 static jlong RuntimeShader_getNativeFinalizer(JNIEnv*, jobject) {
-    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Effect_safeUnref));
+    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&SkRuntimeShaderBuilder_delete));
+}
+
+static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderBuilder, jlong matrixPtr,
+                                  jboolean isOpaque) {
+    SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
+    const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
+    sk_sp<SkShader> shader = builder->makeShader(matrix, isOpaque == JNI_TRUE);
+    ThrowIAE_IfNull(env, shader);
+    return reinterpret_cast<jlong>(shader.release());
+}
+
+static inline int ThrowIAEFmt(JNIEnv* env, const char* fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+    int ret = jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", fmt, args);
+    va_end(args);
+    return ret;
+}
+
+static void RuntimeShader_updateUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
+                                         jstring jUniformName, jfloatArray jvalues) {
+    SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
+    ScopedUtfChars name(env, jUniformName);
+    AutoJavaFloatArray autoValues(env, jvalues, 0, kRO_JNIAccess);
+
+    SkRuntimeShaderBuilder::BuilderUniform uniform = builder->uniform(name.c_str());
+    if (uniform.fVar == nullptr) {
+        ThrowIAEFmt(env, "unable to find uniform named %s", name.c_str());
+    } else if (!uniform.set<float>(autoValues.ptr(), autoValues.length())) {
+        ThrowIAEFmt(env, "mismatch in byte size for uniform [expected: %zu actual: %zu]",
+              uniform.fVar->sizeInBytes(), sizeof(float) * autoValues.length());
+    }
+}
+
+static void RuntimeShader_updateShader(JNIEnv* env, jobject, jlong shaderBuilder,
+                                           jstring jUniformName, jlong shaderHandle) {
+    SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
+    ScopedUtfChars name(env, jUniformName);
+    SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
+
+    SkRuntimeShaderBuilder::BuilderChild child = builder->child(name.c_str());
+    if (child.fIndex == -1) {
+        ThrowIAEFmt(env, "unable to find shader named %s", name.c_str());
+        return;
+    }
+
+    builder->child(name.c_str()) = sk_ref_sp(shader);
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
@@ -313,10 +336,11 @@
 };
 
 static const JNINativeMethod gRuntimeShaderMethods[] = {
-    { "nativeGetFinalizer",   "()J",    (void*)RuntimeShader_getNativeFinalizer },
-    { "nativeCreate",     "(JJ[B[JJZ)J",  (void*)RuntimeShader_create     },
-    { "nativeCreateShaderFactory",     "(Ljava/lang/String;)J",
-      (void*)RuntimeShader_createShaderFactory     },
+        {"nativeGetFinalizer", "()J", (void*)RuntimeShader_getNativeFinalizer},
+        {"nativeCreateShader", "(JJZ)J", (void*)RuntimeShader_create},
+        {"nativeCreateBuilder", "(Ljava/lang/String;)J", (void*)RuntimeShader_createShaderBuilder},
+        {"nativeUpdateUniforms", "(JLjava/lang/String;[F)V", (void*)RuntimeShader_updateUniforms},
+        {"nativeUpdateShader", "(JLjava/lang/String;J)V", (void*)RuntimeShader_updateShader},
 };
 
 int register_android_graphics_Shader(JNIEnv* env)
diff --git a/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp b/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp
index 360492d..855d56e 100644
--- a/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp
+++ b/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp
@@ -144,7 +144,8 @@
 static void android_view_DisplayListCanvas_drawRippleProps(CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr,
                                                            jlong xPropPtr, jlong yPropPtr,
                                                            jlong radiusPropPtr, jlong paintPropPtr,
-                                                           jlong progressPropPtr, jlong effectPtr) {
+                                                           jlong progressPropPtr,
+                                                           jlong builderPtr) {
     Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
     CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr);
     CanvasPropertyPrimitive* yProp = reinterpret_cast<CanvasPropertyPrimitive*>(yPropPtr);
@@ -152,8 +153,8 @@
     CanvasPropertyPaint* paintProp = reinterpret_cast<CanvasPropertyPaint*>(paintPropPtr);
     CanvasPropertyPrimitive* progressProp =
             reinterpret_cast<CanvasPropertyPrimitive*>(progressPropPtr);
-    SkRuntimeEffect* effect = reinterpret_cast<SkRuntimeEffect*>(effectPtr);
-    canvas->drawRipple(xProp, yProp, radiusProp, paintProp, progressProp, sk_ref_sp(effect));
+    SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(builderPtr);
+    canvas->drawRipple(xProp, yProp, radiusProp, paintProp, progressProp, *builder);
 }
 
 static void android_view_DisplayListCanvas_drawWebViewFunctor(CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr, jint functor) {
diff --git a/libs/hwui/pipeline/skia/AnimatedDrawables.h b/libs/hwui/pipeline/skia/AnimatedDrawables.h
index 3142d92..7859145 100644
--- a/libs/hwui/pipeline/skia/AnimatedDrawables.h
+++ b/libs/hwui/pipeline/skia/AnimatedDrawables.h
@@ -61,13 +61,13 @@
                    uirenderer::CanvasPropertyPrimitive* radius,
                    uirenderer::CanvasPropertyPaint* paint,
                    uirenderer::CanvasPropertyPrimitive* progress,
-                   sk_sp<SkRuntimeEffect> runtimeEffect)
+                   const SkRuntimeShaderBuilder& effectBuilder)
             : mX(x)
             , mY(y)
             , mRadius(radius)
             , mPaint(paint)
             , mProgress(progress)
-            , mRuntimeEffectBuilder(std::move(runtimeEffect)) {}
+            , mRuntimeEffectBuilder(effectBuilder) {}
 
 protected:
     virtual SkRect onGetBounds() override {
@@ -83,7 +83,7 @@
         }
 
         SkRuntimeShaderBuilder::BuilderUniform radiusU =
-                mRuntimeEffectBuilder.uniform("in_maxRadius");
+                mRuntimeEffectBuilder.uniform("in_radius");
         if (radiusU.fVar != nullptr) {
             radiusU = mRadius->value;
         }
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
index e6c6e10..3498f71 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
@@ -102,12 +102,12 @@
     bool hasBackwardProjectedNodesSubtree = false;
 
     for (auto& child : mChildNodes) {
-        hasBackwardProjectedNodesHere |= child.getNodeProperties().getProjectBackwards();
         RenderNode* childNode = child.getRenderNode();
         Matrix4 mat4(child.getRecordedMatrix());
         info.damageAccumulator->pushTransform(&mat4);
         info.hasBackwardProjectedNodes = false;
         childFn(childNode, observer, info, functorsNeedLayer);
+        hasBackwardProjectedNodesHere |= child.getNodeProperties().getProjectBackwards();
         hasBackwardProjectedNodesSubtree |= info.hasBackwardProjectedNodes;
         info.damageAccumulator->popTransform();
     }
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 0b4bb75..ee7c4d8 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -94,9 +94,9 @@
                                      uirenderer::CanvasPropertyPrimitive* radius,
                                      uirenderer::CanvasPropertyPaint* paint,
                                      uirenderer::CanvasPropertyPrimitive* progress,
-                                     sk_sp<SkRuntimeEffect> runtimeEffect) {
+                                     const SkRuntimeShaderBuilder& effectBuilder) {
     drawDrawable(mDisplayList->allocateDrawable<AnimatedRipple>(x, y, radius, paint, progress,
-                                                                runtimeEffect));
+                                                                effectBuilder));
 }
 
 void SkiaRecordingCanvas::enableZ(bool enableZ) {
@@ -308,10 +308,13 @@
     SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
     sk_sp<SkImage> image = bitmap.makeImage();
 
+    // HWUI always draws 9-patches with linear filtering, regardless of the Paint.
+    const SkFilterMode filter = SkFilterMode::kLinear;
+
     applyLooper(get_looper(paint), filterBitmap(paint), [&](SkScalar x, SkScalar y,
                 const SkPaint* p) {
-        mRecorder.drawImageLattice(image, lattice, dst.makeOffset(x, y), Paint_to_filter(p),
-                                   p, bitmap.palette());
+        mRecorder.drawImageLattice(image, lattice, dst.makeOffset(x, y), filter, p,
+                                   bitmap.palette());
     });
 
     if (!bitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) {
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
index 0b543ae..8d7a21a 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -72,7 +72,7 @@
                             uirenderer::CanvasPropertyPrimitive* radius,
                             uirenderer::CanvasPropertyPaint* paint,
                             uirenderer::CanvasPropertyPrimitive* progress,
-                            sk_sp<SkRuntimeEffect> runtimeEffect) override;
+                            const SkRuntimeShaderBuilder& effectBuilder) override;
 
     virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override;
 
diff --git a/media/java/android/media/metrics/IPlaybackMetricsManager.aidl b/media/java/android/media/metrics/IPlaybackMetricsManager.aidl
index a1b13ba..e55678d9 100644
--- a/media/java/android/media/metrics/IPlaybackMetricsManager.aidl
+++ b/media/java/android/media/metrics/IPlaybackMetricsManager.aidl
@@ -19,6 +19,8 @@
 import android.media.metrics.NetworkEvent;
 import android.media.metrics.PlaybackErrorEvent;
 import android.media.metrics.PlaybackMetrics;
+import android.media.metrics.PlaybackStateEvent;
+import android.media.metrics.TrackChangeEvent;
 
 /**
  * Interface to the playback manager service.
@@ -27,6 +29,8 @@
 interface IPlaybackMetricsManager {
     void reportPlaybackMetrics(in String sessionId, in PlaybackMetrics metrics, int userId);
     String getSessionId(int userId);
-    void reportPlaybackErrorEvent(in String sessionId, in PlaybackErrorEvent event, int userId);
     void reportNetworkEvent(in String sessionId, in NetworkEvent event, int userId);
+    void reportPlaybackErrorEvent(in String sessionId, in PlaybackErrorEvent event, int userId);
+    void reportPlaybackStateEvent(in String sessionId, in PlaybackStateEvent event, int userId);
+    void reportTrackChangeEvent(in String sessionId, in TrackChangeEvent event, int userId);
 }
\ No newline at end of file
diff --git a/media/java/android/media/metrics/PlaybackMetrics.java b/media/java/android/media/metrics/PlaybackMetrics.java
index 82a5803..070b4e4 100644
--- a/media/java/android/media/metrics/PlaybackMetrics.java
+++ b/media/java/android/media/metrics/PlaybackMetrics.java
@@ -16,11 +16,19 @@
 
 package android.media.metrics;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import com.android.internal.util.AnnotationValidations;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -28,38 +36,323 @@
  * @hide
  */
 public final class PlaybackMetrics implements Parcelable {
-    private int mStreamSourceType;
+    // TODO(b/177209128): JavaDoc for the constants.
+    public static final int STREAM_SOURCE_UNKNOWN = 0;
+    public static final int STREAM_SOURCE_NETWORK = 1;
+    public static final int STREAM_SOURCE_DEVICE = 2;
+    public static final int STREAM_SOURCE_MIXED = 3;
+
+    public static final int STREAM_TYPE_UNKNOWN = 0;
+    public static final int STREAM_TYPE_OTHER = 1;
+    public static final int STREAM_TYPE_PROGRESSIVE = 2;
+    public static final int STREAM_TYPE_DASH = 3;
+    public static final int STREAM_TYPE_HLS = 4;
+    public static final int STREAM_TYPE_SS = 5;
+
+    public static final int PLAYBACK_TYPE_VOD = 0;
+    public static final int PLAYBACK_TYPE_LIVE = 1;
+    public static final int PLAYBACK_TYPE_OTHER = 2;
+
+    public static final int DRM_TYPE_NONE = 0;
+    public static final int DRM_TYPE_OTHER = 1;
+    public static final int DRM_TYPE_PLAY_READY = 2;
+    public static final int DRM_TYPE_WIDEVINE_L1 = 3;
+    public static final int DRM_TYPE_WIDEVINE_L3 = 4;
+    // TODO: add DRM_TYPE_CLEARKEY
+
+    public static final int CONTENT_TYPE_MAIN = 0;
+    public static final int CONTENT_TYPE_AD = 1;
+    public static final int CONTENT_TYPE_OTHER = 2;
+
+
+    /** @hide */
+    @IntDef(prefix = "STREAM_SOURCE_", value = {
+        STREAM_SOURCE_UNKNOWN,
+        STREAM_SOURCE_NETWORK,
+        STREAM_SOURCE_DEVICE,
+        STREAM_SOURCE_MIXED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface StreamSource {}
+
+    /** @hide */
+    @IntDef(prefix = "STREAM_TYPE_", value = {
+        STREAM_TYPE_UNKNOWN,
+        STREAM_TYPE_OTHER,
+        STREAM_TYPE_PROGRESSIVE,
+        STREAM_TYPE_DASH,
+        STREAM_TYPE_HLS,
+        STREAM_TYPE_SS
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface StreamType {}
+
+    /** @hide */
+    @IntDef(prefix = "PLAYBACK_TYPE_", value = {
+        PLAYBACK_TYPE_VOD,
+        PLAYBACK_TYPE_LIVE,
+        PLAYBACK_TYPE_OTHER
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PlaybackType {}
+
+    /** @hide */
+    @IntDef(prefix = "DRM_TYPE_", value = {
+        DRM_TYPE_NONE,
+        DRM_TYPE_OTHER,
+        DRM_TYPE_PLAY_READY,
+        DRM_TYPE_WIDEVINE_L1,
+        DRM_TYPE_WIDEVINE_L3
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DrmType {}
+
+    /** @hide */
+    @IntDef(prefix = "CONTENT_TYPE_", value = {
+        CONTENT_TYPE_MAIN,
+        CONTENT_TYPE_AD,
+        CONTENT_TYPE_OTHER
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ContentType {}
+
+
+
+    private final long mMediaDurationMillis;
+    private final int mStreamSource;
+    private final int mStreamType;
+    private final int mPlaybackType;
+    private final int mDrmType;
+    private final int mContentType;
+    private final @Nullable String mPlayerName;
+    private final @Nullable String mPlayerVersion;
+    private final @NonNull long[] mExperimentIds;
+    private final int mVideoFramesPlayed;
+    private final int mVideoFramesDropped;
+    private final int mAudioUnderrunCount;
+    private final long mNetworkBytesRead;
+    private final long mLocalBytesRead;
+    private final long mNetworkTransferDurationMillis;
 
     /**
      * Creates a new PlaybackMetrics.
      *
      * @hide
      */
-    public PlaybackMetrics(int streamSourceType) {
-        this.mStreamSourceType = streamSourceType;
+    public PlaybackMetrics(
+            long mediaDurationMillis,
+            int streamSource,
+            int streamType,
+            int playbackType,
+            int drmType,
+            int contentType,
+            @Nullable String playerName,
+            @Nullable String playerVersion,
+            @NonNull long[] experimentIds,
+            int videoFramesPlayed,
+            int videoFramesDropped,
+            int audioUnderrunCount,
+            long networkBytesRead,
+            long localBytesRead,
+            long networkTransferDurationMillis) {
+        this.mMediaDurationMillis = mediaDurationMillis;
+        this.mStreamSource = streamSource;
+        this.mStreamType = streamType;
+        this.mPlaybackType = playbackType;
+        this.mDrmType = drmType;
+        this.mContentType = contentType;
+        this.mPlayerName = playerName;
+        this.mPlayerVersion = playerVersion;
+        this.mExperimentIds = experimentIds;
+        AnnotationValidations.validate(NonNull.class, null, mExperimentIds);
+        this.mVideoFramesPlayed = videoFramesPlayed;
+        this.mVideoFramesDropped = videoFramesDropped;
+        this.mAudioUnderrunCount = audioUnderrunCount;
+        this.mNetworkBytesRead = networkBytesRead;
+        this.mLocalBytesRead = localBytesRead;
+        this.mNetworkTransferDurationMillis = networkTransferDurationMillis;
     }
 
-    public int getStreamSourceType() {
-        return mStreamSourceType;
+    public long getMediaDurationMillis() {
+        return mMediaDurationMillis;
+    }
+
+    /**
+     * Gets stream source type.
+     */
+    @StreamSource
+    public int getStreamSource() {
+        return mStreamSource;
+    }
+
+    /**
+     * Gets stream type.
+     */
+    @StreamType
+    public int getStreamType() {
+        return mStreamType;
+    }
+
+
+    /**
+     * Gets playback type.
+     */
+    @PlaybackType
+    public int getPlaybackType() {
+        return mPlaybackType;
+    }
+
+    /**
+     * Gets DRM type.
+     */
+    @DrmType
+    public int getDrmType() {
+        return mDrmType;
+    }
+
+    /**
+     * Gets content type.
+     */
+    @ContentType
+    public int getContentType() {
+        return mContentType;
+    }
+
+    /**
+     * Gets player name.
+     */
+    public @Nullable String getPlayerName() {
+        return mPlayerName;
+    }
+
+    /**
+     * Gets player version.
+     */
+    public @Nullable String getPlayerVersion() {
+        return mPlayerVersion;
+    }
+
+    /**
+     * Gets experiment IDs.
+     */
+    public @NonNull long[] getExperimentIds() {
+        return Arrays.copyOf(mExperimentIds, mExperimentIds.length);
+    }
+
+    /**
+     * Gets video frames played.
+     */
+    public int getVideoFramesPlayed() {
+        return mVideoFramesPlayed;
+    }
+
+    /**
+     * Gets video frames dropped.
+     */
+    public int getVideoFramesDropped() {
+        return mVideoFramesDropped;
+    }
+
+    /**
+     * Gets audio underrun count.
+     */
+    public int getAudioUnderrunCount() {
+        return mAudioUnderrunCount;
+    }
+
+    /**
+     * Gets number of network bytes read.
+     */
+    public long getNetworkBytesRead() {
+        return mNetworkBytesRead;
+    }
+
+    /**
+     * Gets number of local bytes read.
+     */
+    public long getLocalBytesRead() {
+        return mLocalBytesRead;
+    }
+
+    /**
+     * Gets network transfer duration in milliseconds.
+     */
+    public long getNetworkTransferDurationMillis() {
+        return mNetworkTransferDurationMillis;
+    }
+
+    @Override
+    public String toString() {
+        return "PlaybackMetrics { "
+                + "mediaDurationMillis = " + mMediaDurationMillis + ", "
+                + "streamSource = " + mStreamSource + ", "
+                + "streamType = " + mStreamType + ", "
+                + "playbackType = " + mPlaybackType + ", "
+                + "drmType = " + mDrmType + ", "
+                + "contentType = " + mContentType + ", "
+                + "playerName = " + mPlayerName + ", "
+                + "playerVersion = " + mPlayerVersion + ", "
+                + "experimentIds = " + Arrays.toString(mExperimentIds) + ", "
+                + "videoFramesPlayed = " + mVideoFramesPlayed + ", "
+                + "videoFramesDropped = " + mVideoFramesDropped + ", "
+                + "audioUnderrunCount = " + mAudioUnderrunCount + ", "
+                + "networkBytesRead = " + mNetworkBytesRead + ", "
+                + "localBytesRead = " + mLocalBytesRead + ", "
+                + "networkTransferDurationMillis = " + mNetworkTransferDurationMillis
+                + " }";
     }
 
     @Override
     public boolean equals(@Nullable Object o) {
-
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
         PlaybackMetrics that = (PlaybackMetrics) o;
-        return mStreamSourceType == that.mStreamSourceType;
+        return mMediaDurationMillis == that.mMediaDurationMillis
+                && mStreamSource == that.mStreamSource
+                && mStreamType == that.mStreamType
+                && mPlaybackType == that.mPlaybackType
+                && mDrmType == that.mDrmType
+                && mContentType == that.mContentType
+                && Objects.equals(mPlayerName, that.mPlayerName)
+                && Objects.equals(mPlayerVersion, that.mPlayerVersion)
+                && Arrays.equals(mExperimentIds, that.mExperimentIds)
+                && mVideoFramesPlayed == that.mVideoFramesPlayed
+                && mVideoFramesDropped == that.mVideoFramesDropped
+                && mAudioUnderrunCount == that.mAudioUnderrunCount
+                && mNetworkBytesRead == that.mNetworkBytesRead
+                && mLocalBytesRead == that.mLocalBytesRead
+                && mNetworkTransferDurationMillis == that.mNetworkTransferDurationMillis;
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mStreamSourceType);
+        return Objects.hash(mMediaDurationMillis, mStreamSource, mStreamType, mPlaybackType,
+                mDrmType, mContentType, mPlayerName, mPlayerVersion, mExperimentIds,
+                mVideoFramesPlayed, mVideoFramesDropped, mAudioUnderrunCount, mNetworkBytesRead,
+                mLocalBytesRead, mNetworkTransferDurationMillis);
     }
 
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeInt(mStreamSourceType);
+        long flg = 0;
+        if (mPlayerName != null) flg |= 0x80;
+        if (mPlayerVersion != null) flg |= 0x100;
+        dest.writeLong(flg);
+        dest.writeLong(mMediaDurationMillis);
+        dest.writeInt(mStreamSource);
+        dest.writeInt(mStreamType);
+        dest.writeInt(mPlaybackType);
+        dest.writeInt(mDrmType);
+        dest.writeInt(mContentType);
+        if (mPlayerName != null) dest.writeString(mPlayerName);
+        if (mPlayerVersion != null) dest.writeString(mPlayerVersion);
+        dest.writeLongArray(mExperimentIds);
+        dest.writeInt(mVideoFramesPlayed);
+        dest.writeInt(mVideoFramesDropped);
+        dest.writeInt(mAudioUnderrunCount);
+        dest.writeLong(mNetworkBytesRead);
+        dest.writeLong(mLocalBytesRead);
+        dest.writeLong(mNetworkTransferDurationMillis);
     }
 
     @Override
@@ -69,20 +362,231 @@
 
     /** @hide */
     /* package-private */ PlaybackMetrics(@NonNull Parcel in) {
-        int streamSourceType = in.readInt();
-        this.mStreamSourceType = streamSourceType;
+        long flg = in.readLong();
+        long mediaDurationMillis = in.readLong();
+        int streamSource = in.readInt();
+        int streamType = in.readInt();
+        int playbackType = in.readInt();
+        int drmType = in.readInt();
+        int contentType = in.readInt();
+        String playerName = (flg & 0x80) == 0 ? null : in.readString();
+        String playerVersion = (flg & 0x100) == 0 ? null : in.readString();
+        long[] experimentIds = in.createLongArray();
+        int videoFramesPlayed = in.readInt();
+        int videoFramesDropped = in.readInt();
+        int audioUnderrunCount = in.readInt();
+        long networkBytesRead = in.readLong();
+        long localBytesRead = in.readLong();
+        long networkTransferDurationMillis = in.readLong();
+
+        this.mMediaDurationMillis = mediaDurationMillis;
+        this.mStreamSource = streamSource;
+        this.mStreamType = streamType;
+        this.mPlaybackType = playbackType;
+        this.mDrmType = drmType;
+        this.mContentType = contentType;
+        this.mPlayerName = playerName;
+        this.mPlayerVersion = playerVersion;
+        this.mExperimentIds = experimentIds;
+        AnnotationValidations.validate(NonNull.class, null, mExperimentIds);
+        this.mVideoFramesPlayed = videoFramesPlayed;
+        this.mVideoFramesDropped = videoFramesDropped;
+        this.mAudioUnderrunCount = audioUnderrunCount;
+        this.mNetworkBytesRead = networkBytesRead;
+        this.mLocalBytesRead = localBytesRead;
+        this.mNetworkTransferDurationMillis = networkTransferDurationMillis;
     }
 
     public static final @NonNull Parcelable.Creator<PlaybackMetrics> CREATOR =
             new Parcelable.Creator<PlaybackMetrics>() {
-                @Override
-                public PlaybackMetrics[] newArray(int size) {
-                    return new PlaybackMetrics[size];
-                }
+        @Override
+        public PlaybackMetrics[] newArray(int size) {
+            return new PlaybackMetrics[size];
+        }
 
-                @Override
-                public PlaybackMetrics createFromParcel(@NonNull Parcel in) {
-                    return new PlaybackMetrics(in);
-                }
-            };
+        @Override
+        public PlaybackMetrics createFromParcel(@NonNull Parcel in) {
+            return new PlaybackMetrics(in);
+        }
+    };
+
+    /**
+     * A builder for {@link PlaybackMetrics}
+     */
+    public static final class Builder {
+
+        private long mMediaDurationMillis;
+        private int mStreamSource;
+        private int mStreamType;
+        private int mPlaybackType;
+        private int mDrmType;
+        private int mContentType;
+        private @Nullable String mPlayerName;
+        private @Nullable String mPlayerVersion;
+        private @NonNull List<Long> mExperimentIds = new ArrayList<>();
+        private int mVideoFramesPlayed;
+        private int mVideoFramesDropped;
+        private int mAudioUnderrunCount;
+        private long mNetworkBytesRead;
+        private long mLocalBytesRead;
+        private long mNetworkTransferDurationMillis;
+
+        /**
+         * Creates a new Builder.
+         *
+         * @hide
+         */
+        public Builder() {
+        }
+
+        /**
+         * Sets the media duration in milliseconds.
+         */
+        public @NonNull Builder setMediaDurationMillis(long value) {
+            mMediaDurationMillis = value;
+            return this;
+        }
+
+        /**
+         * Sets the stream source type.
+         */
+        public @NonNull Builder setStreamSource(@StreamSource int value) {
+            mStreamSource = value;
+            return this;
+        }
+
+        /**
+         * Sets the stream type.
+         */
+        public @NonNull Builder setStreamType(@StreamType int value) {
+            mStreamType = value;
+            return this;
+        }
+
+        /**
+         * Sets the playback type.
+         */
+        public @NonNull Builder setPlaybackType(@PlaybackType int value) {
+            mPlaybackType = value;
+            return this;
+        }
+
+        /**
+         * Sets the DRM type.
+         */
+        public @NonNull Builder setDrmType(@StreamType int value) {
+            mDrmType = value;
+            return this;
+        }
+
+        /**
+         * Sets the content type.
+         */
+        public @NonNull Builder setContentType(@ContentType int value) {
+            mContentType = value;
+            return this;
+        }
+
+        /**
+         * Sets the player name.
+         */
+        public @NonNull Builder setPlayerName(@NonNull String value) {
+            mPlayerName = value;
+            return this;
+        }
+
+        /**
+         * Sets the player version.
+         */
+        public @NonNull Builder setPlayerVersion(@NonNull String value) {
+            mPlayerVersion = value;
+            return this;
+        }
+
+        /**
+         * Adds the experiment ID.
+         */
+        public @NonNull Builder addExperimentId(long value) {
+            mExperimentIds.add(value);
+            return this;
+        }
+
+        /**
+         * Sets the video frames played.
+         */
+        public @NonNull Builder setVideoFramesPlayed(int value) {
+            mVideoFramesPlayed = value;
+            return this;
+        }
+
+        /**
+         * Sets the video frames dropped.
+         */
+        public @NonNull Builder setVideoFramesDropped(int value) {
+            mVideoFramesDropped = value;
+            return this;
+        }
+
+        /**
+         * Sets the audio underrun count.
+         */
+        public @NonNull Builder setAudioUnderrunCount(int value) {
+            mAudioUnderrunCount = value;
+            return this;
+        }
+
+        /**
+         * Sets the number of network bytes read.
+         */
+        public @NonNull Builder setNetworkBytesRead(long value) {
+            mNetworkBytesRead = value;
+            return this;
+        }
+
+        /**
+         * Sets the number of local bytes read.
+         */
+        public @NonNull Builder setLocalBytesRead(long value) {
+            mLocalBytesRead = value;
+            return this;
+        }
+
+        /**
+         * Sets the network transfer duration in milliseconds.
+         */
+        public @NonNull Builder setNetworkTransferDurationMillis(long value) {
+            mNetworkTransferDurationMillis = value;
+            return this;
+        }
+
+        /** Builds the instance. This builder should not be touched after calling this! */
+        public @NonNull PlaybackMetrics build() {
+
+            PlaybackMetrics o = new PlaybackMetrics(
+                    mMediaDurationMillis,
+                    mStreamSource,
+                    mStreamType,
+                    mPlaybackType,
+                    mDrmType,
+                    mContentType,
+                    mPlayerName,
+                    mPlayerVersion,
+                    idsToLongArray(),
+                    mVideoFramesPlayed,
+                    mVideoFramesDropped,
+                    mAudioUnderrunCount,
+                    mNetworkBytesRead,
+                    mLocalBytesRead,
+                    mNetworkTransferDurationMillis);
+            return o;
+        }
+
+        private long[] idsToLongArray() {
+            long[] ids = new long[mExperimentIds.size()];
+            for (int i = 0; i < mExperimentIds.size(); i++) {
+                ids[i] = mExperimentIds.get(i);
+            }
+            return ids;
+        }
+    }
 }
diff --git a/media/java/android/media/metrics/PlaybackMetricsManager.java b/media/java/android/media/metrics/PlaybackMetricsManager.java
index 95f64ea..f48ffe7 100644
--- a/media/java/android/media/metrics/PlaybackMetricsManager.java
+++ b/media/java/android/media/metrics/PlaybackMetricsManager.java
@@ -61,6 +61,30 @@
     }
 
     /**
+     * Reports playback state event.
+     * @hide
+     */
+    public void reportPlaybackStateEvent(@NonNull String sessionId, PlaybackStateEvent event) {
+        try {
+            mService.reportPlaybackStateEvent(sessionId, event, mUserId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Reports track change event.
+     * @hide
+     */
+    public void reportTrackChangeEvent(@NonNull String sessionId, TrackChangeEvent event) {
+        try {
+            mService.reportTrackChangeEvent(sessionId, event, mUserId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Creates a playback session.
      */
     public PlaybackSession createSession() {
diff --git a/media/java/android/media/metrics/PlaybackSession.java b/media/java/android/media/metrics/PlaybackSession.java
index 3e2f4e1..0a77516 100644
--- a/media/java/android/media/metrics/PlaybackSession.java
+++ b/media/java/android/media/metrics/PlaybackSession.java
@@ -64,6 +64,20 @@
         mManager.reportNetworkEvent(mId, event);
     }
 
+    /**
+     * Reports playback state event.
+     */
+    public void reportPlaybackStateEvent(PlaybackStateEvent event) {
+        mManager.reportPlaybackStateEvent(mId, event);
+    }
+
+    /**
+     * Reports track change event.
+     */
+    public void reportTrackChangeEvent(TrackChangeEvent event) {
+        mManager.reportTrackChangeEvent(mId, event);
+    }
+
     public @NonNull String getId() {
         return mId;
     }
diff --git a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl b/media/java/android/media/metrics/PlaybackStateEvent.aidl
similarity index 64%
copy from media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl
copy to media/java/android/media/metrics/PlaybackStateEvent.aidl
index edf96dd..8b8d05b 100644
--- a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl
+++ b/media/java/android/media/metrics/PlaybackStateEvent.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.
@@ -14,17 +14,6 @@
  * limitations under the License.
  */
 
-package android.media.tv.tunerresourcemanager;
+package android.media.metrics;
 
-/**
- * Simple container of the FrontendInfo struct defined in the TunerHAL 1.0 interface.
- *
- * @hide
- */
-parcelable TunerFrontendInfo {
-    int handle;
-
-    int frontendType;
-
-    int exclusiveGroupId;
-}
+parcelable PlaybackStateEvent;
diff --git a/media/java/android/media/metrics/PlaybackStateEvent.java b/media/java/android/media/metrics/PlaybackStateEvent.java
new file mode 100644
index 0000000..6ce5bf0
--- /dev/null
+++ b/media/java/android/media/metrics/PlaybackStateEvent.java
@@ -0,0 +1,153 @@
+/*
+ * 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.media.metrics;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.util.Objects;
+
+/**
+ * Playback state event.
+ * @hide
+ */
+public final class PlaybackStateEvent implements Parcelable {
+    // TODO: more states
+    /** Playback has not started (initial state) */
+    public static final int STATE_NOT_STARTED = 0;
+    /** Playback is buffering in the background for initial playback start */
+    public static final int STATE_JOINING_BACKGROUND = 1;
+    /** Playback is buffering in the foreground for initial playback start */
+    public static final int STATE_JOINING_FOREGROUND = 2;
+    /** Playback is actively playing */
+    public static final int STATE_PLAYING = 3;
+    /** Playback is paused but ready to play */
+    public static final int STATE_PAUSED = 4;
+
+    private int mState;
+    private long mTimeSincePlaybackCreatedMillis;
+
+    // These track ExoPlayer states. See the ExoPlayer documentation for the state transitions.
+    @IntDef(prefix = "STATE_", value = {
+        STATE_NOT_STARTED,
+        STATE_JOINING_BACKGROUND,
+        STATE_JOINING_FOREGROUND,
+        STATE_PLAYING,
+        STATE_PAUSED
+    })
+    @Retention(java.lang.annotation.RetentionPolicy.SOURCE)
+    public @interface State {}
+
+    /**
+     * Converts playback state to string.
+     */
+    public static String stateToString(@State int value) {
+        switch (value) {
+            case STATE_NOT_STARTED:
+                return "STATE_NOT_STARTED";
+            case STATE_JOINING_BACKGROUND:
+                return "STATE_JOINING_BACKGROUND";
+            case STATE_JOINING_FOREGROUND:
+                return "STATE_JOINING_FOREGROUND";
+            case STATE_PLAYING:
+                return "STATE_PLAYING";
+            case STATE_PAUSED:
+                return "STATE_PAUSED";
+            default:
+                return Integer.toHexString(value);
+        }
+    }
+
+    /**
+     * Creates a new PlaybackStateEvent.
+     *
+     * @hide
+     */
+    public PlaybackStateEvent(
+            int state,
+            long timeSincePlaybackCreatedMillis) {
+        this.mState = state;
+        this.mTimeSincePlaybackCreatedMillis = timeSincePlaybackCreatedMillis;
+    }
+
+    /**
+     * Gets playback state.
+     * @return
+     */
+    public int getState() {
+        return mState;
+    }
+
+    /**
+     * Gets time since the corresponding playback is created in millisecond.
+     */
+    public long getTimeSincePlaybackCreatedMillis() {
+        return mTimeSincePlaybackCreatedMillis;
+    }
+
+    @Override
+    public boolean equals(@Nullable Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        PlaybackStateEvent that = (PlaybackStateEvent) o;
+        return mState == that.mState
+                && mTimeSincePlaybackCreatedMillis == that.mTimeSincePlaybackCreatedMillis;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mState, mTimeSincePlaybackCreatedMillis);
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mState);
+        dest.writeLong(mTimeSincePlaybackCreatedMillis);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** @hide */
+    /* package-private */ PlaybackStateEvent(@NonNull Parcel in) {
+        int state = in.readInt();
+        long timeSincePlaybackCreatedMillis = in.readLong();
+
+        this.mState = state;
+        this.mTimeSincePlaybackCreatedMillis = timeSincePlaybackCreatedMillis;
+    }
+
+    public static final @NonNull Parcelable.Creator<PlaybackStateEvent> CREATOR =
+            new Parcelable.Creator<PlaybackStateEvent>() {
+        @Override
+        public PlaybackStateEvent[] newArray(int size) {
+            return new PlaybackStateEvent[size];
+        }
+
+        @Override
+        public PlaybackStateEvent createFromParcel(@NonNull Parcel in) {
+            return new PlaybackStateEvent(in);
+        }
+    };
+
+}
diff --git a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl b/media/java/android/media/metrics/TrackChangeEvent.aidl
similarity index 64%
copy from media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl
copy to media/java/android/media/metrics/TrackChangeEvent.aidl
index edf96dd..8fbe4a9 100644
--- a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl
+++ b/media/java/android/media/metrics/TrackChangeEvent.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.
@@ -14,17 +14,6 @@
  * limitations under the License.
  */
 
-package android.media.tv.tunerresourcemanager;
+package android.media.metrics;
 
-/**
- * Simple container of the FrontendInfo struct defined in the TunerHAL 1.0 interface.
- *
- * @hide
- */
-parcelable TunerFrontendInfo {
-    int handle;
-
-    int frontendType;
-
-    int exclusiveGroupId;
-}
+parcelable TrackChangeEvent;
diff --git a/media/java/android/media/metrics/TrackChangeEvent.java b/media/java/android/media/metrics/TrackChangeEvent.java
new file mode 100644
index 0000000..fff0e36
--- /dev/null
+++ b/media/java/android/media/metrics/TrackChangeEvent.java
@@ -0,0 +1,480 @@
+/*
+ * 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.media.metrics;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * Playback track change event.
+ * @hide
+ */
+public final class TrackChangeEvent implements Parcelable {
+    public static final int TRACK_STATE_OFF = 0;
+    public static final int TRACK_STATE_ON = 1;
+
+    public static final int TRACK_CHANGE_REASON_UNKNOWN = 0;
+    public static final int TRACK_CHANGE_REASON_OTHER = 1;
+    public static final int TRACK_CHANGE_REASON_INITIAL = 2;
+    public static final int TRACK_CHANGE_REASON_MANUAL = 3;
+    public static final int TRACK_CHANGE_REASON_ADAPTIVE = 4;
+
+    public static final int TRACK_TYPE_AUDIO = 0;
+    public static final int TRACK_TYPE_VIDEO = 1;
+    public static final int TRACK_TYPE_TEXT = 2;
+
+    private final int mState;
+    private final int mReason;
+    private final @Nullable String mContainerMimeType;
+    private final @Nullable String mSampleMimeType;
+    private final @Nullable String mCodecName;
+    private final int mBitrate;
+    private final long mTimeSincePlaybackCreatedMillis;
+    private final int mType;
+    private final @Nullable String mLanguage;
+    private final @Nullable String mLanguageRegion;
+    private final int mChannelCount;
+    private final int mSampleRate;
+    private final int mWidth;
+    private final int mHeight;
+
+
+
+    /** @hide */
+    @IntDef(prefix = "TRACK_STATE_", value = {
+        TRACK_STATE_OFF,
+        TRACK_STATE_ON
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface TrackState {}
+
+    /** @hide */
+    @IntDef(prefix = "TRACK_CHANGE_REASON_", value = {
+        TRACK_CHANGE_REASON_UNKNOWN,
+        TRACK_CHANGE_REASON_OTHER,
+        TRACK_CHANGE_REASON_INITIAL,
+        TRACK_CHANGE_REASON_MANUAL,
+        TRACK_CHANGE_REASON_ADAPTIVE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface TrackChangeReason {}
+
+    /** @hide */
+    @IntDef(prefix = "TRACK_TYPE_", value = {
+        TRACK_TYPE_AUDIO,
+        TRACK_TYPE_VIDEO,
+        TRACK_TYPE_TEXT
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface TrackType {}
+
+    public TrackChangeEvent(
+            int state,
+            int reason,
+            @Nullable String containerMimeType,
+            @Nullable String sampleMimeType,
+            @Nullable String codecName,
+            int bitrate,
+            long timeSincePlaybackCreatedMillis,
+            int type,
+            @Nullable String language,
+            @Nullable String languageRegion,
+            int channelCount,
+            int sampleRate,
+            int width,
+            int height) {
+        this.mState = state;
+        this.mReason = reason;
+        this.mContainerMimeType = containerMimeType;
+        this.mSampleMimeType = sampleMimeType;
+        this.mCodecName = codecName;
+        this.mBitrate = bitrate;
+        this.mTimeSincePlaybackCreatedMillis = timeSincePlaybackCreatedMillis;
+        this.mType = type;
+        this.mLanguage = language;
+        this.mLanguageRegion = languageRegion;
+        this.mChannelCount = channelCount;
+        this.mSampleRate = sampleRate;
+        this.mWidth = width;
+        this.mHeight = height;
+    }
+
+    @TrackState
+    public int getTrackState() {
+        return mState;
+    }
+
+    @TrackChangeReason
+    public int getTrackChangeReason() {
+        return mReason;
+    }
+
+    public @Nullable String getContainerMimeType() {
+        return mContainerMimeType;
+    }
+
+    public @Nullable String getSampleMimeType() {
+        return mSampleMimeType;
+    }
+
+    public @Nullable String getCodecName() {
+        return mCodecName;
+    }
+
+    public int getBitrate() {
+        return mBitrate;
+    }
+
+    public long getTimeSincePlaybackCreatedMillis() {
+        return mTimeSincePlaybackCreatedMillis;
+    }
+
+    @TrackType
+    public int getTrackType() {
+        return mType;
+    }
+
+    public @Nullable String getLanguage() {
+        return mLanguage;
+    }
+
+    public @Nullable String getLanguageRegion() {
+        return mLanguageRegion;
+    }
+
+    public int getChannelCount() {
+        return mChannelCount;
+    }
+
+    public int getSampleRate() {
+        return mSampleRate;
+    }
+
+    public int getWidth() {
+        return mWidth;
+    }
+
+    public int getHeight() {
+        return mHeight;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        int flg = 0;
+        if (mContainerMimeType != null) flg |= 0x4;
+        if (mSampleMimeType != null) flg |= 0x8;
+        if (mCodecName != null) flg |= 0x10;
+        if (mLanguage != null) flg |= 0x100;
+        if (mLanguageRegion != null) flg |= 0x200;
+        dest.writeInt(flg);
+        dest.writeInt(mState);
+        dest.writeInt(mReason);
+        if (mContainerMimeType != null) dest.writeString(mContainerMimeType);
+        if (mSampleMimeType != null) dest.writeString(mSampleMimeType);
+        if (mCodecName != null) dest.writeString(mCodecName);
+        dest.writeInt(mBitrate);
+        dest.writeLong(mTimeSincePlaybackCreatedMillis);
+        dest.writeInt(mType);
+        if (mLanguage != null) dest.writeString(mLanguage);
+        if (mLanguageRegion != null) dest.writeString(mLanguageRegion);
+        dest.writeInt(mChannelCount);
+        dest.writeInt(mSampleRate);
+        dest.writeInt(mWidth);
+        dest.writeInt(mHeight);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** @hide */
+    /* package-private */ TrackChangeEvent(@NonNull Parcel in) {
+        int flg = in.readInt();
+        int state = in.readInt();
+        int reason = in.readInt();
+        String containerMimeType = (flg & 0x4) == 0 ? null : in.readString();
+        String sampleMimeType = (flg & 0x8) == 0 ? null : in.readString();
+        String codecName = (flg & 0x10) == 0 ? null : in.readString();
+        int bitrate = in.readInt();
+        long timeSincePlaybackCreatedMillis = in.readLong();
+        int type = in.readInt();
+        String language = (flg & 0x100) == 0 ? null : in.readString();
+        String languageRegion = (flg & 0x200) == 0 ? null : in.readString();
+        int channelCount = in.readInt();
+        int sampleRate = in.readInt();
+        int width = in.readInt();
+        int height = in.readInt();
+
+        this.mState = state;
+        this.mReason = reason;
+        this.mContainerMimeType = containerMimeType;
+        this.mSampleMimeType = sampleMimeType;
+        this.mCodecName = codecName;
+        this.mBitrate = bitrate;
+        this.mTimeSincePlaybackCreatedMillis = timeSincePlaybackCreatedMillis;
+        this.mType = type;
+        this.mLanguage = language;
+        this.mLanguageRegion = languageRegion;
+        this.mChannelCount = channelCount;
+        this.mSampleRate = sampleRate;
+        this.mWidth = width;
+        this.mHeight = height;
+    }
+
+    public static final @NonNull Parcelable.Creator<TrackChangeEvent> CREATOR =
+            new Parcelable.Creator<TrackChangeEvent>() {
+        @Override
+        public TrackChangeEvent[] newArray(int size) {
+            return new TrackChangeEvent[size];
+        }
+
+        @Override
+        public TrackChangeEvent createFromParcel(@NonNull Parcel in) {
+            return new TrackChangeEvent(in);
+        }
+    };
+
+
+
+    // Code below generated by codegen v1.0.22.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/media/java/android/media/metrics/TrackChangeEvent.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+    @Override
+    public String toString() {
+        return "TrackChangeEvent { " +
+                "state = " + mState + ", " +
+                "reason = " + mReason + ", " +
+                "containerMimeType = " + mContainerMimeType + ", " +
+                "sampleMimeType = " + mSampleMimeType + ", " +
+                "codecName = " + mCodecName + ", " +
+                "bitrate = " + mBitrate + ", " +
+                "timeSincePlaybackCreatedMillis = " + mTimeSincePlaybackCreatedMillis + ", " +
+                "type = " + mType + ", " +
+                "language = " + mLanguage + ", " +
+                "languageRegion = " + mLanguageRegion + ", " +
+                "channelCount = " + mChannelCount + ", " +
+                "sampleRate = " + mSampleRate + ", " +
+                "width = " + mWidth + ", " +
+                "height = " + mHeight +
+        " }";
+    }
+
+    @Override
+    public boolean equals(@Nullable Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        TrackChangeEvent that = (TrackChangeEvent) o;
+        return mState == that.mState
+                && mReason == that.mReason
+                && Objects.equals(mContainerMimeType, that.mContainerMimeType)
+                && Objects.equals(mSampleMimeType, that.mSampleMimeType)
+                && Objects.equals(mCodecName, that.mCodecName)
+                && mBitrate == that.mBitrate
+                && mTimeSincePlaybackCreatedMillis == that.mTimeSincePlaybackCreatedMillis
+                && mType == that.mType
+                && Objects.equals(mLanguage, that.mLanguage)
+                && Objects.equals(mLanguageRegion, that.mLanguageRegion)
+                && mChannelCount == that.mChannelCount
+                && mSampleRate == that.mSampleRate
+                && mWidth == that.mWidth
+                && mHeight == that.mHeight;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mState, mReason, mContainerMimeType, mSampleMimeType, mCodecName,
+                mBitrate, mTimeSincePlaybackCreatedMillis, mType, mLanguage, mLanguageRegion,
+                mChannelCount, mSampleRate, mWidth, mHeight);
+    }
+
+    /**
+     * A builder for {@link TrackChangeEvent}
+     */
+    public static final class Builder {
+        // TODO: check track type for the setters.
+        private int mState;
+        private int mReason;
+        private @Nullable String mContainerMimeType;
+        private @Nullable String mSampleMimeType;
+        private @Nullable String mCodecName;
+        private int mBitrate;
+        private long mTimeSincePlaybackCreatedMillis;
+        private int mType;
+        private @Nullable String mLanguage;
+        private @Nullable String mLanguageRegion;
+        private int mChannelCount;
+        private int mSampleRate;
+        private int mWidth;
+        private int mHeight;
+
+        private long mBuilderFieldsSet = 0L;
+
+        /**
+         * Creates a new Builder.
+         *
+         * @hide
+         */
+        public Builder(int type) {
+            mType = type;
+        }
+
+        public @NonNull Builder setTrackState(@TrackState int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x1;
+            mState = value;
+            return this;
+        }
+
+        public @NonNull Builder setTrackChangeReason(@TrackChangeReason int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x2;
+            mReason = value;
+            return this;
+        }
+
+        public @NonNull Builder setContainerMimeType(@NonNull String value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x4;
+            mContainerMimeType = value;
+            return this;
+        }
+
+        public @NonNull Builder setSampleMimeType(@NonNull String value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x8;
+            mSampleMimeType = value;
+            return this;
+        }
+
+        public @NonNull Builder setCodecName(@NonNull String value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x10;
+            mCodecName = value;
+            return this;
+        }
+
+        public @NonNull Builder setBitrate(int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x20;
+            mBitrate = value;
+            return this;
+        }
+
+        public @NonNull Builder setTimeSincePlaybackCreatedMillis(long value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x40;
+            mTimeSincePlaybackCreatedMillis = value;
+            return this;
+        }
+
+        public @NonNull Builder setTrackType(@TrackType int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x80;
+            mType = value;
+            return this;
+        }
+
+        public @NonNull Builder setLanguage(@NonNull String value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x100;
+            mLanguage = value;
+            return this;
+        }
+
+        public @NonNull Builder setLanguageRegion(@NonNull String value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x200;
+            mLanguageRegion = value;
+            return this;
+        }
+
+        public @NonNull Builder setChannelCount(int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x400;
+            mChannelCount = value;
+            return this;
+        }
+
+        public @NonNull Builder setSampleRate(int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x800;
+            mSampleRate = value;
+            return this;
+        }
+
+        public @NonNull Builder setWidth(int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x1000;
+            mWidth = value;
+            return this;
+        }
+
+        public @NonNull Builder setHeight(int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x2000;
+            mHeight = value;
+            return this;
+        }
+
+        /** Builds the instance. This builder should not be touched after calling this! */
+        public @NonNull TrackChangeEvent build() {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x4000; // Mark builder used
+
+            TrackChangeEvent o = new TrackChangeEvent(
+                    mState,
+                    mReason,
+                    mContainerMimeType,
+                    mSampleMimeType,
+                    mCodecName,
+                    mBitrate,
+                    mTimeSincePlaybackCreatedMillis,
+                    mType,
+                    mLanguage,
+                    mLanguageRegion,
+                    mChannelCount,
+                    mSampleRate,
+                    mWidth,
+                    mHeight);
+            return o;
+        }
+
+        private void checkNotUsed() {
+            if ((mBuilderFieldsSet & 0x4000) != 0) {
+                throw new IllegalStateException(
+                        "This Builder should not be reused. Use a new Builder instance instead");
+            }
+        }
+    }
+}
diff --git a/media/java/android/media/tv/TvInputHardwareInfo.java b/media/java/android/media/tv/TvInputHardwareInfo.java
index b12f7c5..1249e0d 100644
--- a/media/java/android/media/tv/TvInputHardwareInfo.java
+++ b/media/java/android/media/tv/TvInputHardwareInfo.java
@@ -188,6 +188,17 @@
         mCableConnectionStatus = source.readInt();
     }
 
+    /** @hide */
+    public Builder toBuilder() {
+        return new Builder()
+            .deviceId(mDeviceId)
+            .type(mType)
+            .audioType(mAudioType)
+            .audioAddress(mAudioAddress)
+            .hdmiPortId(mHdmiPortId)
+            .cableConnectionStatus(mCableConnectionStatus);
+    }
+
     public static final class Builder {
         private Integer mDeviceId = null;
         private Integer mType = null;
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 46b29f5..7192c07 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -988,9 +988,11 @@
     }
 
     /**
-     * Gets the initialized frontend information.
+     * Gets the currently initialized and activated frontend information. To get all the available
+     * frontend info on the device, use {@link getAvailableFrontendInfos()}.
      *
-     * @return The frontend information. {@code null} if the operation failed.
+     * @return The active frontend information. {@code null} if the operation failed.
+     * @throws IllegalStateException if there is no active frontend currently.
      */
     @Nullable
     public FrontendInfo getFrontendInfo() {
@@ -1007,13 +1009,20 @@
     }
 
     /**
-     * Get a list all the existed frontend information.
+     * Gets a list of all the available frontend information on the device. To get the information
+     * of the currently active frontend, use {@link getFrontendInfo()}. The active frontend
+     * information is also included in the list of the available frontend information.
      *
-     * @return The list of all the frontend information. {@code null} if the operation failed.
+     * @return The list of all the available frontend information. {@code null} if the operation
+     * failed.
      */
     @Nullable
-    public List<FrontendInfo> getFrontendInfoList() {
-        return Arrays.asList(getFrontendInfoListInternal());
+    public List<FrontendInfo> getAvailableFrontendInfos() {
+        FrontendInfo[] feInfoList = getFrontendInfoListInternal();
+        if (feInfoList == null) {
+            return null;
+        }
+        return Arrays.asList(feInfoList);
     }
 
     /** @hide */
diff --git a/media/java/android/media/tv/tunerresourcemanager/Android.bp b/media/java/android/media/tv/tunerresourcemanager/Android.bp
index 02390bb..c38d919 100644
--- a/media/java/android/media/tv/tunerresourcemanager/Android.bp
+++ b/media/java/android/media/tv/tunerresourcemanager/Android.bp
@@ -1,16 +1,7 @@
 filegroup {
     name: "framework-media-tv-tunerresourcemanager-sources-aidl",
     srcs: [
-        "aidl/android/media/tv/tunerresourcemanager/CasSessionRequest.aidl",
-        "aidl/android/media/tv/tunerresourcemanager/IResourcesReclaimListener.aidl",
-        "aidl/android/media/tv/tunerresourcemanager/ResourceClientProfile.aidl",
-        "aidl/android/media/tv/tunerresourcemanager/TunerCiCamRequest.aidl",
-        "aidl/android/media/tv/tunerresourcemanager/TunerDemuxRequest.aidl",
-        "aidl/android/media/tv/tunerresourcemanager/TunerDescramblerRequest.aidl",
-        "aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl",
-        "aidl/android/media/tv/tunerresourcemanager/TunerFrontendRequest.aidl",
-        "aidl/android/media/tv/tunerresourcemanager/TunerLnbRequest.aidl",
-        "aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl",
+        "aidl/android/media/tv/tunerresourcemanager/*.aidl",
     ],
     path: "aidl",
 }
@@ -21,7 +12,7 @@
     local_include_dir: "aidl",
     backend: {
         java: {
-            sdk_version: "current",
+            enabled: true,
         },
         cpp: {
             enabled: true,
@@ -33,4 +24,5 @@
     srcs: [
         ":framework-media-tv-tunerresourcemanager-sources-aidl",
     ],
+    imports: ["tv_tuner_frontend_info_aidl_interface"],
 }
diff --git a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
index 6f7adbc..e399fbd 100644
--- a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
+++ b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
@@ -24,6 +24,7 @@
 import android.annotation.SystemService;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.media.tv.tuner.TunerFrontendInfo;
 import android.os.Binder;
 import android.os.RemoteException;
 import android.util.Log;
diff --git a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
index a1f6687..483d972 100644
--- a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
+++ b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
@@ -16,13 +16,13 @@
 
 package android.media.tv.tunerresourcemanager;
 
+import android.media.tv.tuner.TunerFrontendInfo;
 import android.media.tv.tunerresourcemanager.CasSessionRequest;
 import android.media.tv.tunerresourcemanager.IResourcesReclaimListener;
 import android.media.tv.tunerresourcemanager.ResourceClientProfile;
 import android.media.tv.tunerresourcemanager.TunerCiCamRequest;
 import android.media.tv.tunerresourcemanager.TunerDemuxRequest;
 import android.media.tv.tunerresourcemanager.TunerDescramblerRequest;
-import android.media.tv.tunerresourcemanager.TunerFrontendInfo;
 import android.media.tv.tunerresourcemanager.TunerFrontendRequest;
 import android.media.tv.tunerresourcemanager.TunerLnbRequest;
 
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 798bf6e..4f27b197 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -27,10 +27,14 @@
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.graphics.Bitmap;
+import android.media.ApplicationMediaCapabilities;
 import android.media.ExifInterface;
+import android.media.MediaFormat;
 import android.media.ThumbnailUtils;
 import android.net.Uri;
 import android.os.BatteryManager;
+import android.os.Bundle;
+import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.storage.StorageVolume;
 import android.provider.MediaStore;
@@ -52,6 +56,7 @@
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
@@ -754,6 +759,32 @@
         return MtpConstants.RESPONSE_OK;
     }
 
+    @VisibleForNative
+    private int openFilePath(String path, boolean transcode) {
+        Uri uri = MediaStore.scanFile(mContext.getContentResolver(), new File(path));
+        if (uri == null) {
+            Log.i(TAG, "Failed to obtain URI for openFile with transcode support: " + path);
+            return -1;
+        }
+
+        try {
+            Log.i(TAG, "openFile with transcode support: " + path);
+            // TODO(b/158466651): Pass the |transcode| variable as flag to openFile
+            Bundle bundle = null;
+            if (!transcode) {
+                bundle = new Bundle();
+                bundle.putParcelable(MediaStore.EXTRA_MEDIA_CAPABILITIES,
+                        new ApplicationMediaCapabilities.Builder().addSupportedVideoMimeType(
+                                MediaFormat.MIMETYPE_VIDEO_HEVC).build());
+            }
+            return mMediaProvider.openTypedAssetFileDescriptor(uri, "*/*", bundle)
+                    .getParcelFileDescriptor().detachFd();
+        } catch (RemoteException | FileNotFoundException e) {
+            Log.w(TAG, "Failed to openFile with transcode support: " + path, e);
+            return -1;
+        }
+    }
+
     private int getObjectFormat(int handle) {
         MtpStorageManager.MtpObject obj = mManager.getObject(handle);
         if (obj == null) {
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index 17189fd..4efdcac 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -63,6 +63,7 @@
 static jmethodID method_getObjectPropertyList;
 static jmethodID method_getObjectInfo;
 static jmethodID method_getObjectFilePath;
+static jmethodID method_openFilePath;
 static jmethodID method_getThumbnailInfo;
 static jmethodID method_getThumbnailData;
 static jmethodID method_beginDeleteObject;
@@ -160,6 +161,7 @@
                                             MtpStringBuffer& outFilePath,
                                             int64_t& outFileLength,
                                             MtpObjectFormat& outFormat);
+    virtual int                     openFilePath(const char* path, bool transcode);
     virtual MtpResponseCode         beginDeleteObject(MtpObjectHandle handle);
     virtual void                    endDeleteObject(MtpObjectHandle handle, bool succeeded);
 
@@ -969,6 +971,17 @@
     return result;
 }
 
+int MtpDatabase::openFilePath(const char* path, bool transcode) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jstring pathStr = env->NewStringUTF(path);
+    jint result = env->CallIntMethod(mDatabase, method_openFilePath, pathStr, transcode);
+
+    if (result < 0) {
+        checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    }
+    return result;
+}
+
 MtpResponseCode MtpDatabase::beginDeleteObject(MtpObjectHandle handle) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     MtpResponseCode result = env->CallIntMethod(mDatabase, method_beginDeleteObject, (jint)handle);
@@ -1333,6 +1346,7 @@
     GET_METHOD_ID(getObjectPropertyList, clazz, "(IIIII)Landroid/mtp/MtpPropertyList;");
     GET_METHOD_ID(getObjectInfo, clazz, "(I[I[C[J)Z");
     GET_METHOD_ID(getObjectFilePath, clazz, "(I[C[J)I");
+    GET_METHOD_ID(openFilePath, clazz, "(Ljava/lang/String;Z)I");
     GET_METHOD_ID(getThumbnailInfo, clazz, "(I[J)Z");
     GET_METHOD_ID(getThumbnailData, clazz, "(I)[B");
     GET_METHOD_ID(beginDeleteObject, clazz, "(I)I");
diff --git a/media/jni/tuner/TunerClient.cpp b/media/jni/tuner/TunerClient.cpp
index a26753d..f5e3524 100644
--- a/media/jni/tuner/TunerClient.cpp
+++ b/media/jni/tuner/TunerClient.cpp
@@ -25,8 +25,6 @@
 using ::android::hardware::tv::tuner::V1_0::FrontendId;
 using ::android::hardware::tv::tuner::V1_0::FrontendType;
 
-using ::aidl::android::media::tv::tunerresourcemanager::TunerFrontendInfo;
-
 namespace android {
 
 sp<ITuner> TunerClient::mTuner;
@@ -104,7 +102,7 @@
         int id;
         // TODO: handle error code
         tunerFrontend->getFrontendId(&id);
-        TunerServiceFrontendInfo aidlFrontendInfo;
+        TunerFrontendInfo aidlFrontendInfo;
         // TODO: handle error code
         mTunerService->getFrontendInfo(id, &aidlFrontendInfo);
         return new FrontendClient(tunerFrontend, frontendHandle, aidlFrontendInfo.type);
@@ -130,7 +128,7 @@
 
 shared_ptr<FrontendInfo> TunerClient::getFrontendInfo(int id) {
     if (mTunerService != NULL) {
-        TunerServiceFrontendInfo aidlFrontendInfo;
+        TunerFrontendInfo aidlFrontendInfo;
         // TODO: handle error code
         mTunerService->getFrontendInfo(id, &aidlFrontendInfo);
         return make_shared<FrontendInfo>(FrontendInfoAidlToHidl(aidlFrontendInfo));
@@ -303,7 +301,7 @@
         }
         TunerFrontendInfo tunerFrontendInfo{
             .handle = getResourceHandleFromId((int)ids[i], FRONTEND),
-            .frontendType = static_cast<int>(frontendInfo->type),
+            .type = static_cast<int>(frontendInfo->type),
             .exclusiveGroupId = static_cast<int>(frontendInfo->exclusiveGroupId),
         };
         infos.push_back(tunerFrontendInfo);
@@ -452,7 +450,7 @@
     return lnbHandles;
 }
 
-FrontendInfo TunerClient::FrontendInfoAidlToHidl(TunerServiceFrontendInfo aidlFrontendInfo) {
+FrontendInfo TunerClient::FrontendInfoAidlToHidl(TunerFrontendInfo aidlFrontendInfo) {
     FrontendInfo hidlFrontendInfo {
         .type = static_cast<FrontendType>(aidlFrontendInfo.type),
         .minFrequency = static_cast<uint32_t>(aidlFrontendInfo.minFrequency),
diff --git a/media/jni/tuner/TunerClient.h b/media/jni/tuner/TunerClient.h
index a3d2d02c..8a1181a 100644
--- a/media/jni/tuner/TunerClient.h
+++ b/media/jni/tuner/TunerClient.h
@@ -18,8 +18,8 @@
 #define _ANDROID_MEDIA_TV_TUNER_CLIENT_H_
 
 #include <aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.h>
-#include <aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.h>
 #include <aidl/android/media/tv/tuner/ITunerService.h>
+#include <aidl/android/media/tv/tuner/TunerFrontendInfo.h>
 #include <android/hardware/tv/tuner/1.1/ITuner.h>
 #include <android/hardware/tv/tuner/1.1/types.h>
 
@@ -29,7 +29,7 @@
 #include "LnbClient.h"
 
 using ::aidl::android::media::tv::tuner::ITunerService;
-using ::aidl::android::media::tv::tuner::TunerServiceFrontendInfo;
+using ::aidl::android::media::tv::tuner::TunerFrontendInfo;
 using ::aidl::android::media::tv::tunerresourcemanager::ITunerResourceManager;
 
 using ::android::hardware::tv::tuner::V1_0::DemuxCapabilities;
@@ -141,7 +141,7 @@
     sp<ILnb> openHidlLnbByName(string name, LnbId& lnbId);
     sp<IDescrambler> openHidlDescrambler();
     vector<int> getLnbHandles();
-    FrontendInfo FrontendInfoAidlToHidl(TunerServiceFrontendInfo aidlFrontendInfo);
+    FrontendInfo FrontendInfoAidlToHidl(TunerFrontendInfo aidlFrontendInfo);
     void updateTunerResources();
     void updateFrontendResources();
     void updateLnbResources();
diff --git a/native/graphics/jni/Android.bp b/native/graphics/jni/Android.bp
index b9aefdd..3751564 100644
--- a/native/graphics/jni/Android.bp
+++ b/native/graphics/jni/Android.bp
@@ -89,6 +89,13 @@
         asan_options: [
             "detect_odr_violation=1",
         ],
+        hwasan_options: [
+             // Image decoders may attempt to allocate a large amount of memory
+             // (especially if the encoded image is large). This doesn't
+             // necessarily mean there is a bug. Set allocator_may_return_null=1
+             // for hwasan so the fuzzer can continue running.
+            "allocator_may_return_null = 1",
+        ],
     },
     corpus: ["corpus/*"],
     host_supported: true,
diff --git a/native/graphics/jni/imagedecoder.cpp b/native/graphics/jni/imagedecoder.cpp
index eab5f41..385e455 100644
--- a/native/graphics/jni/imagedecoder.cpp
+++ b/native/graphics/jni/imagedecoder.cpp
@@ -353,7 +353,7 @@
         return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
     }
 
-    SkISize size = toDecoder(decoder)->mCodec->getSampledDimensions(sampleSize);
+    SkISize size = toDecoder(decoder)->getSampledDimensions(sampleSize);
     *width = size.width();
     *height = size.height();
     return ANDROID_IMAGE_DECODER_SUCCESS;
diff --git a/packages/CompanionDeviceManager/res/values-af/strings.xml b/packages/CompanionDeviceManager/res/values-af/strings.xml
index d366a0b..cdf4851 100644
--- a/packages/CompanionDeviceManager/res/values-af/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-af/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Metgeseltoestel-bestuurder"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"horlosie"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Stel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; om jou <xliff:g id="PROFILE_NAME">%2$s</xliff:g> te bestuur – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"Jy het <xliff:g id="APP_NAME">%1$s</xliff:g> nodig om jou <xliff:g id="PROFILE_NAME">%2$s</xliff:g> te bestuur. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Ja"</string>
     <string name="consent_no" msgid="1335543792857823917">"Nee, dankie"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-am/strings.xml b/packages/CompanionDeviceManager/res/values-am/strings.xml
index 68e816a..a03ea0df 100644
--- a/packages/CompanionDeviceManager/res/values-am/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-am/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"አጃቢ የመሣሪያ አስተዳዳሪ"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"ሰዓት"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; የእርስዎን <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; እንዲያስተዳድር ያቀናብሩት"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> የእርስዎን <xliff:g id="PROFILE_NAME">%2$s</xliff:g> ለማስተዳደር ያስፈልጋል። <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"አዎ"</string>
     <string name="consent_no" msgid="1335543792857823917">"አይ፣ አመሰግናለሁ"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ar/strings.xml b/packages/CompanionDeviceManager/res/values-ar/strings.xml
index 184837f..970c46b 100644
--- a/packages/CompanionDeviceManager/res/values-ar/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ar/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"تطبيق \"مدير الجهاز المصاحب\""</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"ساعة"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"‏اضبط &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; لإدارة <xliff:g id="PROFILE_NAME">%2$s</xliff:g> على &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"يجب توفّر تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> لإدارة <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"نعم"</string>
     <string name="consent_no" msgid="1335543792857823917">"لا، شكرًا"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-as/strings.xml b/packages/CompanionDeviceManager/res/values-as/strings.xml
index 116d63b..477844c 100644
--- a/packages/CompanionDeviceManager/res/values-as/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-as/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"কম্পেনিয়ন ডিভাইচ মেনেজাৰ"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"ঘড়ী"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"আপোনাৰ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> পৰিচালনা কৰিবলৈ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ছেট কৰক - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"আপোনাৰ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> পৰিচালনা কৰিবলৈ <xliff:g id="APP_NAME">%1$s</xliff:g>ৰ আৱশ্যক। <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"হয়"</string>
     <string name="consent_no" msgid="1335543792857823917">"নালাগে, ধন্যবাদ"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-az/strings.xml b/packages/CompanionDeviceManager/res/values-az/strings.xml
index bc719a3..f10c639 100644
--- a/packages/CompanionDeviceManager/res/values-az/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-az/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Kompanyon Cihaz Meneceri"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"izləyin"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> profilinizin &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tərəfindən idarə olunmasını ayarlayın - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> profilinizi idarə etmək üçün <xliff:g id="APP_NAME">%1$s</xliff:g> tələb olunur. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Bəli"</string>
     <string name="consent_no" msgid="1335543792857823917">"Xeyr, çox sağolun"</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 a0e5298..e8542f3 100644
--- a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Menadžer pridruženog uređaja"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"sat"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Podesite aplikaciju &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da upravlja profilom <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je neophodna za upravljanje profilom <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Da"</string>
     <string name="consent_no" msgid="1335543792857823917">"Ne, hvala"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-be/strings.xml b/packages/CompanionDeviceManager/res/values-be/strings.xml
index 96a513d..13be6f2 100644
--- a/packages/CompanionDeviceManager/res/values-be/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-be/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Менеджар спадарожнай прылады"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"гадзіннік"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Дазвольце праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; кіраваць прыладай \"<xliff:g id="PROFILE_NAME">%2$s</xliff:g>\" – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"Для кіравання прыладай \"<xliff:g id="PROFILE_NAME">%2$s</xliff:g>\" патрабуецца праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\". <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Так"</string>
     <string name="consent_no" msgid="1335543792857823917">"Не, дзякуй"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-bg/strings.xml b/packages/CompanionDeviceManager/res/values-bg/strings.xml
index 3775dbe..3bda5e6 100644
--- a/packages/CompanionDeviceManager/res/values-bg/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bg/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"часовник"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Задайте &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да управлява устройството ви (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>) – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"За управление на <xliff:g id="PROFILE_NAME">%2$s</xliff:g> се изисква <xliff:g id="APP_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Да"</string>
     <string name="consent_no" msgid="1335543792857823917">"Не, благодаря"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-bn/strings.xml b/packages/CompanionDeviceManager/res/values-bn/strings.xml
index 1e8fd0b..d3bc515 100644
--- a/packages/CompanionDeviceManager/res/values-bn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bn/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"দেখুন"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"আপনার <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; ম্যানেজ করার জন্য &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; সেট করুন"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g>-কে আপনার <xliff:g id="PROFILE_NAME">%2$s</xliff:g>.ম্যানেজ করতে দিতে হবে। <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"হ্যাঁ"</string>
     <string name="consent_no" msgid="1335543792857823917">"না থাক"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-bs/strings.xml b/packages/CompanionDeviceManager/res/values-bs/strings.xml
index 133aea3..905b306 100644
--- a/packages/CompanionDeviceManager/res/values-bs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bs/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Prateći upravitelj uređaja"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"sat"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Postavite aplikaciju &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da upravlja vašim uređajem <xliff:g id="PROFILE_NAME">%2$s</xliff:g> — &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"Potrebna je aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> za upravljanje uređajem <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Da"</string>
     <string name="consent_no" msgid="1335543792857823917">"Ne, hvala"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ca/strings.xml b/packages/CompanionDeviceManager/res/values-ca/strings.xml
index cf26b08..86dc694 100644
--- a/packages/CompanionDeviceManager/res/values-ca/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ca/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Gestor de dispositius complementaris"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"rellotge"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Defineix que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gestioni el teu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> (&lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;)"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"L\'aplicació <xliff:g id="APP_NAME">%1$s</xliff:g> és necessària per gestionar el teu <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Sí"</string>
     <string name="consent_no" msgid="1335543792857823917">"No, gràcies"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-da/strings.xml b/packages/CompanionDeviceManager/res/values-da/strings.xml
index 30a331a..5a31f9b 100644
--- a/packages/CompanionDeviceManager/res/values-da/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-da/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Medfølgende enhedshåndtering"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"ur"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Angiv &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; til administration af: <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> er nødvendig for at administrere: <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Ja"</string>
     <string name="consent_no" msgid="1335543792857823917">"Nej tak"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-el/strings.xml b/packages/CompanionDeviceManager/res/values-el/strings.xml
index 4867a8e..60de2ff 100644
--- a/packages/CompanionDeviceManager/res/values-el/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-el/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Διαχείριση συνοδευτικής εφαρμογής"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"ρολόι"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Ορίστε μια εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; για διαχείριση του προφίλ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> απαιτείται για τη διαχείριση του προφίλ <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Ναι"</string>
     <string name="consent_no" msgid="1335543792857823917">"Όχι, ευχαριστώ"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
index a0e5091..2fed1ae 100644
--- a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Set &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> is needed to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Yes"</string>
     <string name="consent_no" msgid="1335543792857823917">"No, thanks"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
index a0e5091..2fed1ae 100644
--- a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Set &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> is needed to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Yes"</string>
     <string name="consent_no" msgid="1335543792857823917">"No, thanks"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
index a0e5091..2fed1ae 100644
--- a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Set &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> is needed to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Yes"</string>
     <string name="consent_no" msgid="1335543792857823917">"No, thanks"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
index a0e5091..2fed1ae 100644
--- a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Set &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> is needed to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Yes"</string>
     <string name="consent_no" msgid="1335543792857823917">"No, thanks"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
index 5780fb4..4fbb57e 100644
--- a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Administrador de dispositivo complementario"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"reloj"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Configura &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; para administrar <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"Se requiere <xliff:g id="APP_NAME">%1$s</xliff:g> para administrar tu <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Sí"</string>
     <string name="consent_no" msgid="1335543792857823917">"No, gracias"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-es/strings.xml b/packages/CompanionDeviceManager/res/values-es/strings.xml
index 78cfa5a..5ca9305 100644
--- a/packages/CompanionDeviceManager/res/values-es/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Gestor de dispositivos complementario"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"reloj"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Haz que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gestione tu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"Se necesita <xliff:g id="APP_NAME">%1$s</xliff:g> para gestionar tu <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Sí"</string>
     <string name="consent_no" msgid="1335543792857823917">"No, gracias"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-et/strings.xml b/packages/CompanionDeviceManager/res/values-et/strings.xml
index 3f29da0..357f052 100644
--- a/packages/CompanionDeviceManager/res/values-et/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-et/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Kaasseadme haldur"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"käekell"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Määrake rakendus &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; haldama teie seadet <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> on vajalik teie seadme <xliff:g id="PROFILE_NAME">%2$s</xliff:g> haldamiseks. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Jah"</string>
     <string name="consent_no" msgid="1335543792857823917">"Tänan, ei"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-eu/strings.xml b/packages/CompanionDeviceManager/res/values-eu/strings.xml
index 30907a2..14c7154 100644
--- a/packages/CompanionDeviceManager/res/values-eu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-eu/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Gailu osagarriaren kudeatzailea"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"erlojua"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Konfiguratu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; <xliff:g id="PROFILE_NAME">%2$s</xliff:g> (&lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;) kudea dezan"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> erabili behar duzu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> kudeatzeko. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Bai"</string>
     <string name="consent_no" msgid="1335543792857823917">"Ez"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-fa/strings.xml b/packages/CompanionDeviceManager/res/values-fa/strings.xml
index 9e1ecb1..6bb9620 100644
--- a/packages/CompanionDeviceManager/res/values-fa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fa/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"مدیر دستگاه مرتبط"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"ساعت"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"‏تنظیم &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; برای مدیریت کردن <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>‏&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"برای مدیریت کردن <xliff:g id="PROFILE_NAME">%2$s</xliff:g> به <xliff:g id="APP_NAME">%1$s</xliff:g> نیاز دارید. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"بله"</string>
     <string name="consent_no" msgid="1335543792857823917">"نه متشکرم"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-fi/strings.xml b/packages/CompanionDeviceManager/res/values-fi/strings.xml
index 4a1f13f..5a9c1cd 100644
--- a/packages/CompanionDeviceManager/res/values-fi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fi/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"kello"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Aseta &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; profiilin (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>) hallinnoijaksi – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> tarvitaan profiilin (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>) hallinnointiin. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Kyllä"</string>
     <string name="consent_no" msgid="1335543792857823917">"Ei kiitos"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
index ce5e262..b31babd 100644
--- a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Gestionnaire d\'appareil compagnon"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"montre"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Utiliser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pour gérer votre <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"L\'application <xliff:g id="APP_NAME">%1$s</xliff:g> est requise pour gérer votre <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Oui"</string>
     <string name="consent_no" msgid="1335543792857823917">"Non merci"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-fr/strings.xml b/packages/CompanionDeviceManager/res/values-fr/strings.xml
index e15639b..08c93a2c 100644
--- a/packages/CompanionDeviceManager/res/values-fr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Gestionnaire d\'appareils associés"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"montre"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Définir &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pour la gestion de votre <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> est requis pour gérer votre <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Oui"</string>
     <string name="consent_no" msgid="1335543792857823917">"Non, merci"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-gl/strings.xml b/packages/CompanionDeviceManager/res/values-gl/strings.xml
index 1205e46..c95b90e 100644
--- a/packages/CompanionDeviceManager/res/values-gl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gl/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Xestor de dispositivos complementarios"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"reloxo"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Define a aplicación &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; para a xestión do teu perfil (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>): &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"Necesítase a aplicación <xliff:g id="APP_NAME">%1$s</xliff:g> para xestionar o teu perfil (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>). <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Si"</string>
     <string name="consent_no" msgid="1335543792857823917">"Non, grazas"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-hi/strings.xml b/packages/CompanionDeviceManager/res/values-hi/strings.xml
index 80c0d95..ac95cc6 100644
--- a/packages/CompanionDeviceManager/res/values-hi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hi/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"सहयोगी डिवाइस मैनेजर"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"स्मार्टवॉच"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"अपने <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; को प्रबंधित करने के लिए, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को सेट करें"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"आपके <xliff:g id="PROFILE_NAME">%2$s</xliff:g> को प्रबंधित करने के लिए, <xliff:g id="APP_NAME">%1$s</xliff:g> की ज़रूरत है. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"हां"</string>
     <string name="consent_no" msgid="1335543792857823917">"नहीं, रहने दें"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-hr/strings.xml b/packages/CompanionDeviceManager/res/values-hr/strings.xml
index b574ff6..df8451f 100644
--- a/packages/CompanionDeviceManager/res/values-hr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hr/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"satom"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Postavite aplikaciju &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da upravlja vašim profilom <xliff:g id="PROFILE_NAME">%2$s</xliff:g> –- &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> potrebna je za upravljanje vašim <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Da"</string>
     <string name="consent_no" msgid="1335543792857823917">"Ne, hvala"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-hu/strings.xml b/packages/CompanionDeviceManager/res/values-hu/strings.xml
index b271b12..ff1c6c5 100644
--- a/packages/CompanionDeviceManager/res/values-hu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hu/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Társeszközök kezelője"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"óra"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"A(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; alkalmazás beállítása a(z) <xliff:g id="PROFILE_NAME">%2$s</xliff:g> (&lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;) kezelésére"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"Szükség van a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazásra a(z) <xliff:g id="PROFILE_NAME">%2$s</xliff:g> kezeléséhez. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Igen"</string>
     <string name="consent_no" msgid="1335543792857823917">"Nem"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-hy/strings.xml b/packages/CompanionDeviceManager/res/values-hy/strings.xml
index e865690..194223d 100644
--- a/packages/CompanionDeviceManager/res/values-hy/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hy/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"ժամացույց"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Ընտրեք &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածը որպես <xliff:g id="PROFILE_NAME">%2$s</xliff:g>ի կառավարիչ․ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"Ձեր <xliff:g id="PROFILE_NAME">%2$s</xliff:g>ը կառավարելու համար անհրաժեշտ է <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը։ <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Այո"</string>
     <string name="consent_no" msgid="1335543792857823917">"Ոչ, շնորհակալություն"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-in/strings.xml b/packages/CompanionDeviceManager/res/values-in/strings.xml
index 2d4fd4a..58bf3cb 100644
--- a/packages/CompanionDeviceManager/res/values-in/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-in/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Pengelola Perangkat Pendamping"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"smartwatch"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Tetapkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; untuk mengelola <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"Perlu <xliff:g id="APP_NAME">%1$s</xliff:g> untuk mengelola <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Ya"</string>
     <string name="consent_no" msgid="1335543792857823917">"Tidak"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-is/strings.xml b/packages/CompanionDeviceManager/res/values-is/strings.xml
index 8698bfb..cc5b989 100644
--- a/packages/CompanionDeviceManager/res/values-is/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-is/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Stjórnun fylgdartækja"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"úr"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Veita &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; stjórn á <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> er krafist til að stjórna <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Já"</string>
     <string name="consent_no" msgid="1335543792857823917">"Nei, takk"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-it/strings.xml b/packages/CompanionDeviceManager/res/values-it/strings.xml
index beb1482..4cbefd8 100644
--- a/packages/CompanionDeviceManager/res/values-it/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-it/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Gestione dispositivi companion"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"orologio"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Configura &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; per gestire il tuo <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"È richiesta l\'app <xliff:g id="APP_NAME">%1$s</xliff:g> per gestire il tuo <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Sì"</string>
     <string name="consent_no" msgid="1335543792857823917">"No, grazie"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ja/strings.xml b/packages/CompanionDeviceManager/res/values-ja/strings.xml
index b50c56a..b695d9d 100644
--- a/packages/CompanionDeviceManager/res/values-ja/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ja/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"コンパニオン デバイス マネージャ"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"ウォッチ"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; で <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; を管理するよう設定する"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> を管理するために <xliff:g id="APP_NAME">%1$s</xliff:g> が必要です。<xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"はい"</string>
     <string name="consent_no" msgid="1335543792857823917">"いいえ"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ka/strings.xml b/packages/CompanionDeviceManager/res/values-ka/strings.xml
index 4ab0abd..300c94f 100644
--- a/packages/CompanionDeviceManager/res/values-ka/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ka/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"კომპანიონი მოწყობილობების მენეჯერი"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"საათი"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"დააყენეთ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;, რომ მართოს თქვენი <xliff:g id="PROFILE_NAME">%2$s</xliff:g> — &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"თქვენი <xliff:g id="PROFILE_NAME">%2$s</xliff:g>-ის სამართავად საჭიროა <xliff:g id="APP_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"დიახ"</string>
     <string name="consent_no" msgid="1335543792857823917">"არა, გმადლობთ"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-kk/strings.xml b/packages/CompanionDeviceManager/res/values-kk/strings.xml
index fcfe030..94d6c3e 100644
--- a/packages/CompanionDeviceManager/res/values-kk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kk/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"сағат"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>) құрылғысын басқаруға рұқсат беру"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> құрылғысын басқару үшін <xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы керек. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Иә"</string>
     <string name="consent_no" msgid="1335543792857823917">"Жоқ, рақмет"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-km/strings.xml b/packages/CompanionDeviceManager/res/values-km/strings.xml
index e708004..db13fe7 100644
--- a/packages/CompanionDeviceManager/res/values-km/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-km/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"កម្មវិធី​គ្រប់​គ្រង​ឧបករណ៍ដៃគូ"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"នាឡិកា"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"កំណត់ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ដើម្បីគ្រប់គ្រង <xliff:g id="PROFILE_NAME">%2$s</xliff:g> របស់អ្នក - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"ចាំបាច់ត្រូវមាន <xliff:g id="APP_NAME">%1$s</xliff:g> ដើម្បីគ្រប់គ្រង <xliff:g id="PROFILE_NAME">%2$s</xliff:g> របស់អ្នក។ <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"បាទ/ចាស"</string>
     <string name="consent_no" msgid="1335543792857823917">"ទេ អរគុណ"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ko/strings.xml b/packages/CompanionDeviceManager/res/values-ko/strings.xml
index 299d586..1363e57 100644
--- a/packages/CompanionDeviceManager/res/values-ko/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ko/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"부속 기기 관리자"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"시계"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;에서 <xliff:g id="PROFILE_NAME">%2$s</xliff:g>(&lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;)을(를) 관리하도록 설정"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> 프로필을 관리하려면 <xliff:g id="APP_NAME">%1$s</xliff:g> 앱이 필요합니다. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"예"</string>
     <string name="consent_no" msgid="1335543792857823917">"취소"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ky/strings.xml b/packages/CompanionDeviceManager/res/values-ky/strings.xml
index 35ee34d..c01e235 100644
--- a/packages/CompanionDeviceManager/res/values-ky/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ky/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"саат"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; түзмөгүңүздү башкарсын"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> профилиңизди башкаруу үчүн <xliff:g id="APP_NAME">%1$s</xliff:g> керек. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Ооба"</string>
     <string name="consent_no" msgid="1335543792857823917">"Жок, рахмат"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-lo/strings.xml b/packages/CompanionDeviceManager/res/values-lo/strings.xml
index a27bc15..68218dd 100644
--- a/packages/CompanionDeviceManager/res/values-lo/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lo/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"ຕົວຈັດການອຸປະກອນປະກອບ"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"ໂມງ"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"ຕັ້ງ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ເພື່ອຈັດການ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; ຂອງທ່ານ"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"ຕ້ອງໃຊ້ <xliff:g id="APP_NAME">%1$s</xliff:g> ເພື່ອຈັດການ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> ຂອງທ່ານ. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"ແມ່ນແລ້ວ"</string>
     <string name="consent_no" msgid="1335543792857823917">"ບໍ່, ຂອບໃຈ"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-lt/strings.xml b/packages/CompanionDeviceManager/res/values-lt/strings.xml
index 11510ac..5fd8280 100644
--- a/packages/CompanionDeviceManager/res/values-lt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lt/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"laikrodis"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Nustatyti, kad <xliff:g id="PROFILE_NAME">%2$s</xliff:g> &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; būtų valdomas programos &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"Norint valdyti jūsų <xliff:g id="PROFILE_NAME">%2$s</xliff:g>, reikalinga programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Taip"</string>
     <string name="consent_no" msgid="1335543792857823917">"Ne, ačiū"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-lv/strings.xml b/packages/CompanionDeviceManager/res/values-lv/strings.xml
index 6a85c83..bf036ec 100644
--- a/packages/CompanionDeviceManager/res/values-lv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lv/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Palīgierīču pārzinis"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"pulkstenis"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Lietotnes &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; iestatīšana profila (<xliff:g id="PROFILE_NAME">%2$s</xliff:g> — &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;) pārvaldībai"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"Lai pārvaldītu profilu (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>), nepieciešama lietotne <xliff:g id="APP_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Jā"</string>
     <string name="consent_no" msgid="1335543792857823917">"Nē, paldies"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-mk/strings.xml b/packages/CompanionDeviceManager/res/values-mk/strings.xml
index 6fed96b..427ca8f 100644
--- a/packages/CompanionDeviceManager/res/values-mk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mk/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"часовник"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Поставете ја &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да управува со <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> е потребна за да управува со <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Да"</string>
     <string name="consent_no" msgid="1335543792857823917">"Не, фала"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ml/strings.xml b/packages/CompanionDeviceManager/res/values-ml/strings.xml
index 6b071cd..a48c45f 100644
--- a/packages/CompanionDeviceManager/res/values-ml/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ml/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"കമ്പാനിയൻ ഉപകരണ മാനേജർ"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"വാച്ച്"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"നിങ്ങളുടെ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> മാനേജ് ചെയ്യുന്നതിന് &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; സജ്ജീകരിക്കുക - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്ന ആപ്പിന് നിങ്ങളുടെ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> മാനേജ് ചെയ്യേണ്ടതുണ്ട്. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"വേണം"</string>
     <string name="consent_no" msgid="1335543792857823917">"വേണ്ട"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-mn/strings.xml b/packages/CompanionDeviceManager/res/values-mn/strings.xml
index 4d048cb..7ac20e6 100644
--- a/packages/CompanionDeviceManager/res/values-mn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mn/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"цаг"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g>-аа удирдахын тулд &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-г тохируулна уу - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"Таны <xliff:g id="PROFILE_NAME">%2$s</xliff:g>-г удирдахын тулд <xliff:g id="APP_NAME">%1$s</xliff:g> шаардлагатай. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Тийм"</string>
     <string name="consent_no" msgid="1335543792857823917">"Үгүй, баярлалаа"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-my/strings.xml b/packages/CompanionDeviceManager/res/values-my/strings.xml
index b16869d..9c2783c 100644
--- a/packages/CompanionDeviceManager/res/values-my/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-my/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"တွဲဖက်ကိရိယာ မန်နေဂျာ"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"နာရီ"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"သင်၏ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; ကို စီမံခန့်ခွဲရန် &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ကို သတ်မှတ်ပါ"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"သင်၏ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> ကို စီမံခန့်ခွဲရန် <xliff:g id="APP_NAME">%1$s</xliff:g> ကို လိုအပ်ပါသည်။ <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Yes"</string>
     <string name="consent_no" msgid="1335543792857823917">"မလိုပါ"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-nb/strings.xml b/packages/CompanionDeviceManager/res/values-nb/strings.xml
index cac087f..26fbb03 100644
--- a/packages/CompanionDeviceManager/res/values-nb/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nb/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"klokke"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Angi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; for å administrere <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> kreves for å administrere <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Ja"</string>
     <string name="consent_no" msgid="1335543792857823917">"Nei takk"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ne/strings.xml b/packages/CompanionDeviceManager/res/values-ne/strings.xml
index e390161..f289b37 100644
--- a/packages/CompanionDeviceManager/res/values-ne/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ne/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"सहयोगी यन्त्रको प्रबन्धक"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"घडी"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"आफ्नो <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; व्यवस्थापन गर्न &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; तोक्नुहोस्"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> व्यवस्थापन गर्न <xliff:g id="APP_NAME">%1$s</xliff:g> इन्स्टल गर्नु पर्ने हुन्छ। <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"अँ"</string>
     <string name="consent_no" msgid="1335543792857823917">"सहमत छुइनँ"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-nl/strings.xml b/packages/CompanionDeviceManager/res/values-nl/strings.xml
index 2153770..0c9cdffd 100644
--- a/packages/CompanionDeviceManager/res/values-nl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nl/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"horloge"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; instellen om je <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; te beheren"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"Je hebt <xliff:g id="APP_NAME">%1$s</xliff:g> nodig om je <xliff:g id="PROFILE_NAME">%2$s</xliff:g> te beheren. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Ja"</string>
     <string name="consent_no" msgid="1335543792857823917">"Nee, bedankt"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-pl/strings.xml b/packages/CompanionDeviceManager/res/values-pl/strings.xml
index b16d045..b07af57 100644
--- a/packages/CompanionDeviceManager/res/values-pl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pl/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Menedżer urządzeń towarzyszących"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"zegarek"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Ustaw aplikację &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; do zarządzania profilem <xliff:g id="PROFILE_NAME">%2$s</xliff:g> na urządzeniu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> jest wymagana do zarządzania profilem <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Tak"</string>
     <string name="consent_no" msgid="1335543792857823917">"Nie, dziękuję"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
index 40f9d2d..16906f6 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Gerenciador de dispositivos complementar"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Defina o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; como gerenciador do seu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> (&lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;)"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> é necessário para gerenciar seu <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Sim"</string>
     <string name="consent_no" msgid="1335543792857823917">"Agora não"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-pt/strings.xml b/packages/CompanionDeviceManager/res/values-pt/strings.xml
index 40f9d2d..16906f6 100644
--- a/packages/CompanionDeviceManager/res/values-pt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Gerenciador de dispositivos complementar"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Defina o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; como gerenciador do seu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> (&lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;)"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> é necessário para gerenciar seu <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Sim"</string>
     <string name="consent_no" msgid="1335543792857823917">"Agora não"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ro/strings.xml b/packages/CompanionDeviceManager/res/values-ro/strings.xml
index 6040adf..187cfbdf 100644
--- a/packages/CompanionDeviceManager/res/values-ro/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ro/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Manager de dispozitiv Companion"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"ceas"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Setați &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pentru a vă gestiona profilul <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> este necesară pentru a vă gestiona profilul <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Da"</string>
     <string name="consent_no" msgid="1335543792857823917">"Nu, mulțumesc"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ru/strings.xml b/packages/CompanionDeviceManager/res/values-ru/strings.xml
index 9939a82..8dd9a39 100644
--- a/packages/CompanionDeviceManager/res/values-ru/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ru/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Управление подключенными устройствами"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"часы"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Разрешите приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; управлять устройством &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>)"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" необходимо для управления устройством (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>). <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Да"</string>
     <string name="consent_no" msgid="1335543792857823917">"Нет"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-si/strings.xml b/packages/CompanionDeviceManager/res/values-si/strings.xml
index 6e6b029..9e7c02e 100644
--- a/packages/CompanionDeviceManager/res/values-si/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-si/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"සහායක උපාංග කළමනාකරු"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"ඔරලෝසුව"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ඔබගේ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> කළමනාකරණය කිරීමට සකසන්න - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"ඔබගේ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> කළමනාකරණය කිරීමට <xliff:g id="APP_NAME">%1$s</xliff:g> අවශ්‍යයි. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"ඔව්"</string>
     <string name="consent_no" msgid="1335543792857823917">"එපා, ස්තුතියි"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-sk/strings.xml b/packages/CompanionDeviceManager/res/values-sk/strings.xml
index 520aa09..55a47c2 100644
--- a/packages/CompanionDeviceManager/res/values-sk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sk/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Správca sprievodných zariadení"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"hodinky"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Nastavte aplikáciu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;, aby spravovala profil <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"Na správu profilu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> je potrebná aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Áno"</string>
     <string name="consent_no" msgid="1335543792857823917">"Nie, vďaka"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-sl/strings.xml b/packages/CompanionDeviceManager/res/values-sl/strings.xml
index f60cab8..159afd5 100644
--- a/packages/CompanionDeviceManager/res/values-sl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sl/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Upravitelj spremljevalnih naprav"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"ura"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Nastavitev aplikacije &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;, ki bo upravljala napravo <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"Za upravljanje naprave <xliff:g id="PROFILE_NAME">%2$s</xliff:g> potrebujete aplikacijo <xliff:g id="APP_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Da"</string>
     <string name="consent_no" msgid="1335543792857823917">"Ne, hvala"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-sr/strings.xml b/packages/CompanionDeviceManager/res/values-sr/strings.xml
index da08d87..fdbbe8e 100644
--- a/packages/CompanionDeviceManager/res/values-sr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sr/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Менаџер придруженог уређаја"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"сат"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Подесите апликацију &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да управља профилом <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> је неопходна за управљање профилом <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Да"</string>
     <string name="consent_no" msgid="1335543792857823917">"Не, хвала"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-sv/strings.xml b/packages/CompanionDeviceManager/res/values-sv/strings.xml
index a73cbfa..bfd2516 100644
--- a/packages/CompanionDeviceManager/res/values-sv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sv/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"klocka"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Konfigurera &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; för att hantera din <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> krävs för att hantera din <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Ja"</string>
     <string name="consent_no" msgid="1335543792857823917">"Nej tack"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-sw/strings.xml b/packages/CompanionDeviceManager/res/values-sw/strings.xml
index 5865ec9..437ae7f 100644
--- a/packages/CompanionDeviceManager/res/values-sw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sw/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Kidhibiti cha Vifaa Visaidizi"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"saa"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Weka &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ili udhibiti <xliff:g id="PROFILE_NAME">%2$s</xliff:g> yako - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> linahitajika ili kudhibiti <xliff:g id="PROFILE_NAME">%2$s</xliff:g> yako. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Ndiyo"</string>
     <string name="consent_no" msgid="1335543792857823917">"Hapana"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ta/strings.xml b/packages/CompanionDeviceManager/res/values-ta/strings.xml
index f9d6401..9b4a720 100644
--- a/packages/CompanionDeviceManager/res/values-ta/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ta/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"கம்பேனியன் சாதன நிர்வாகி"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"வாட்ச்"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; ஐ நிர்வகிக்க &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அமையுங்கள்"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> ஐ நிர்வகிக்க <xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸ் வேண்டும். <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"ஆம்"</string>
     <string name="consent_no" msgid="1335543792857823917">"வேண்டாம்"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-te/strings.xml b/packages/CompanionDeviceManager/res/values-te/strings.xml
index 82616cc..6e785de 100644
--- a/packages/CompanionDeviceManager/res/values-te/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-te/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"సహచర పరికర మేనేజర్"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"వాచ్"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"మీ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;ను మేనేజ్ చేయడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ను సెటప్ చేయండి"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"మీ <xliff:g id="PROFILE_NAME">%2$s</xliff:g>ను మేనేజ్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> అవసరం ఉంది. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"అవును"</string>
     <string name="consent_no" msgid="1335543792857823917">"వద్దు, ధన్యవాదాలు"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-th/strings.xml b/packages/CompanionDeviceManager/res/values-th/strings.xml
index 77a9fff..b727d42 100644
--- a/packages/CompanionDeviceManager/res/values-th/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-th/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"นาฬิกา"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"ตั้งค่า &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ให้จัดการ<xliff:g id="PROFILE_NAME">%2$s</xliff:g>ของคุณ - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"ต้องใช้ <xliff:g id="APP_NAME">%1$s</xliff:g> ในการจัดการ<xliff:g id="PROFILE_NAME">%2$s</xliff:g> <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"ใช่"</string>
     <string name="consent_no" msgid="1335543792857823917">"ไม่เป็นไร"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-tl/strings.xml b/packages/CompanionDeviceManager/res/values-tl/strings.xml
index 6d62642..a93282a 100644
--- a/packages/CompanionDeviceManager/res/values-tl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tl/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Kasamang Device Manager"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"relo"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Itakda ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; para pamahalaan ang iyong <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"Kailangan ang <xliff:g id="APP_NAME">%1$s</xliff:g> para pamahalaan ang iyong <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Oo"</string>
     <string name="consent_no" msgid="1335543792857823917">"Huwag na lang"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-tr/strings.xml b/packages/CompanionDeviceManager/res/values-tr/strings.xml
index 2c30ea7..3abe064 100644
--- a/packages/CompanionDeviceManager/res/values-tr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tr/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"saat"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasını, <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; cihazınızı yönetecek şekilde ayarlayın"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="PROFILE_NAME">%2$s</xliff:g> yönetimi için gereklidir. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Evet"</string>
     <string name="consent_no" msgid="1335543792857823917">"Hayır, teşekkürler"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-uk/strings.xml b/packages/CompanionDeviceManager/res/values-uk/strings.xml
index f68fd92..161d95e 100644
--- a/packages/CompanionDeviceManager/res/values-uk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uk/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Диспетчер супутніх пристроїв"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"годинник"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Налаштуйте додаток &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;, щоб керувати своїм пристроєм &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>)"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"Щоб керувати своїм пристроєм (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>), вам потрібен додаток <xliff:g id="APP_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Так"</string>
     <string name="consent_no" msgid="1335543792857823917">"Ні, дякую"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-uz/strings.xml b/packages/CompanionDeviceManager/res/values-uz/strings.xml
index c8c4b22..4cce2e8 100644
--- a/packages/CompanionDeviceManager/res/values-uz/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uz/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"tomosha qilish"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt; qurilmalarini boshqarish uchun &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasini sozlang"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi <xliff:g id="PROFILE_NAME">%2$s</xliff:g> qurilmasini boshqarish uchun kerak. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Ha"</string>
     <string name="consent_no" msgid="1335543792857823917">"Kerak emas"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-vi/strings.xml b/packages/CompanionDeviceManager/res/values-vi/strings.xml
index f0234a4..06a1ab6 100644
--- a/packages/CompanionDeviceManager/res/values-vi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-vi/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"đồng hồ"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Đặt &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; để quản lý <xliff:g id="PROFILE_NAME">%2$s</xliff:g> của bạn – &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"Cần có <xliff:g id="APP_NAME">%1$s</xliff:g> để quản lý <xliff:g id="PROFILE_NAME">%2$s</xliff:g> của bạn. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Có"</string>
     <string name="consent_no" msgid="1335543792857823917">"Không, cảm ơn"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
index caf2321..12bfcf3 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"配套设备管理器"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"手表"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"设为由&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;管理您的<xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"若要管理<xliff:g id="PROFILE_NAME">%2$s</xliff:g>,您需要使用<xliff:g id="APP_NAME">%1$s</xliff:g>。<xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"好"</string>
     <string name="consent_no" msgid="1335543792857823917">"不用了"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
index 5ec64a5..0c583b2 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"隨附裝置管理員"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"手錶"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"設定 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 來管理您的 <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"必須使用 <xliff:g id="APP_NAME">%1$s</xliff:g> 來管理您的<xliff:g id="PROFILE_NAME">%2$s</xliff:g>。<xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"是"</string>
     <string name="consent_no" msgid="1335543792857823917">"不用了,謝謝"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
index b8c2ed0..519f0e8 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"隨附裝置管理員"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"手錶"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"授權讓「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;管理你的<xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"如要管理你的<xliff:g id="PROFILE_NAME">%2$s</xliff:g>,必須使用「<xliff:g id="APP_NAME">%1$s</xliff:g>」。<xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"是"</string>
     <string name="consent_no" msgid="1335543792857823917">"不用了,謝謝"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-zu/strings.xml b/packages/CompanionDeviceManager/res/values-zu/strings.xml
index 7df0869..7721b54 100644
--- a/packages/CompanionDeviceManager/res/values-zu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zu/strings.xml
@@ -19,11 +19,9 @@
     <string name="app_label" msgid="4470785958457506021">"Isiphathi sedivayisi esihambisanayo"</string>
     <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>
-    <!-- no translation found for profile_name_watch (576290739483672360) -->
-    <skip />
+    <string name="profile_name_watch" msgid="576290739483672360">"buka"</string>
     <string name="confirmation_title" msgid="4751119145078041732">"Setha i-&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukuba iphathe i-<xliff:g id="PROFILE_NAME">%2$s</xliff:g> - &lt;strong&gt;<xliff:g id="DEVICE_NAME">%3$s</xliff:g>&lt;/strong&gt;"</string>
-    <!-- no translation found for profile_summary (2009764182871566255) -->
-    <skip />
+    <string name="profile_summary" msgid="2009764182871566255">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> iyadingeka ukuphatha i-<xliff:g id="PROFILE_NAME">%2$s</xliff:g> yakho. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
     <string name="consent_yes" msgid="4055438216605487056">"Yebo"</string>
     <string name="consent_no" msgid="1335543792857823917">"Cha ngiyabonga"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-af/arrays.xml b/packages/SettingsLib/res/values-af/arrays.xml
index 93f00e7..ca409f37 100644
--- a/packages/SettingsLib/res/values-af/arrays.xml
+++ b/packages/SettingsLib/res/values-af/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", aktief (media)"</item>
     <item msgid="5001852592115448348">", aktief (foon)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Af"</item>
-    <item msgid="7839165897132179888">"64 K"</item>
-    <item msgid="2715700596495505626">"256 K"</item>
-    <item msgid="7099386891713159947">"1 M"</item>
-    <item msgid="6069075827077845520">"4 M"</item>
-    <item msgid="8243549501764402572">"16 M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Af"</item>
     <item msgid="4064786181089783077">"64 K"</item>
     <item msgid="3052710745383602630">"256 K"</item>
     <item msgid="3691785423374588514">"1 M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Af"</item>
-    <item msgid="4195153527464162486">"64 K per logbuffer"</item>
-    <item msgid="7464037639415220106">"256 K per logbuffer"</item>
-    <item msgid="8539423820514360724">"1 M per logbuffer"</item>
-    <item msgid="1984761927103140651">"4 M per logbuffer"</item>
-    <item msgid="7892098981256010498">"16 M per logbuffer"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Af"</item>
     <item msgid="6014837961827347618">"Alles"</item>
diff --git a/packages/SettingsLib/res/values-am/arrays.xml b/packages/SettingsLib/res/values-am/arrays.xml
index 18696b1..e941c11 100644
--- a/packages/SettingsLib/res/values-am/arrays.xml
+++ b/packages/SettingsLib/res/values-am/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">"፣ ገቢር (ሚዲያ)"</item>
     <item msgid="5001852592115448348">"፣ ገቢር (ስልክ)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"ጠፍቷል"</item>
-    <item msgid="7839165897132179888">"64 ኪባ"</item>
-    <item msgid="2715700596495505626">"256 ኪባ"</item>
-    <item msgid="7099386891713159947">"1 ሜባ"</item>
-    <item msgid="6069075827077845520">"4 ሜባ"</item>
-    <item msgid="8243549501764402572">"16 ሜባ"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"ጠፍቷል"</item>
     <item msgid="4064786181089783077">"64 ኪባ"</item>
     <item msgid="3052710745383602630">"256 ኪባ"</item>
     <item msgid="3691785423374588514">"1 ሜባ"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"ጠፍቷል"</item>
-    <item msgid="4195153527464162486">"64 ኪባ በምዝግብ ማስታወሻ ቋጥ"</item>
-    <item msgid="7464037639415220106">"256 ኪባ በምዝግብ ማስታወሻ ቋጥ"</item>
-    <item msgid="8539423820514360724">"1 ሜ በምዝግብ ማስታወሻ ቋጥ"</item>
-    <item msgid="1984761927103140651">"4 ሜ በምዝግብ ማስታወሻ ቋጥ"</item>
-    <item msgid="7892098981256010498">"16 ሜ በምዝግብ ማስታወሻ ቋጥ"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"ጠፍቷል"</item>
     <item msgid="6014837961827347618">"ሁሉም"</item>
diff --git a/packages/SettingsLib/res/values-ar/arrays.xml b/packages/SettingsLib/res/values-ar/arrays.xml
index d09b50e..db1d4b4 100644
--- a/packages/SettingsLib/res/values-ar/arrays.xml
+++ b/packages/SettingsLib/res/values-ar/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">"، مُفعَّل (وسائط)"</item>
     <item msgid="5001852592115448348">"، مُفعَّل (هاتف)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"إيقاف"</item>
-    <item msgid="7839165897132179888">"٦٤ كيلوبايت"</item>
-    <item msgid="2715700596495505626">"٢٥٦ كيلوبايت"</item>
-    <item msgid="7099386891713159947">"1 ميغابايت"</item>
-    <item msgid="6069075827077845520">"٤ ميغابايت"</item>
-    <item msgid="8243549501764402572">"١٦ ميغابايت"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"إيقاف"</item>
     <item msgid="4064786181089783077">"٦٤ كيلوبايت"</item>
     <item msgid="3052710745383602630">"٢٥٦ كيلوبايت"</item>
     <item msgid="3691785423374588514">"1 ميغابايت"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"إيقاف"</item>
-    <item msgid="4195153527464162486">"٦٤ كيلوبايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
-    <item msgid="7464037639415220106">"٢٥٦ كيلوبايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
-    <item msgid="8539423820514360724">"1 ميغابايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
-    <item msgid="1984761927103140651">"٤ ميغابايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
-    <item msgid="7892098981256010498">"١٦ ميغابايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"إيقاف"</item>
     <item msgid="6014837961827347618">"الكل"</item>
diff --git a/packages/SettingsLib/res/values-as/arrays.xml b/packages/SettingsLib/res/values-as/arrays.xml
index b619d3b..b2494fb 100644
--- a/packages/SettingsLib/res/values-as/arrays.xml
+++ b/packages/SettingsLib/res/values-as/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", সক্ৰিয় (মিডিয়া)"</item>
     <item msgid="5001852592115448348">", সক্ৰিয় (ফ\'ন)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"অফ কৰক"</item>
-    <item msgid="7839165897132179888">"৬৪কে."</item>
-    <item msgid="2715700596495505626">"২৫৬কে."</item>
-    <item msgid="7099386891713159947">"১মি."</item>
-    <item msgid="6069075827077845520">"4M"</item>
-    <item msgid="8243549501764402572">"১৬মি."</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"অফ কৰক"</item>
     <item msgid="4064786181089783077">"৬৪কে."</item>
     <item msgid="3052710745383602630">"২৫৬কে."</item>
     <item msgid="3691785423374588514">"১মি."</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"অফ কৰক"</item>
-    <item msgid="4195153527464162486">"প্ৰতিটো লগ বাফাৰত ৬৪কে."</item>
-    <item msgid="7464037639415220106">"প্ৰতি লগ বাফাৰত 256K"</item>
-    <item msgid="8539423820514360724">"প্ৰতিটো লগ বাফাৰত ১মি."</item>
-    <item msgid="1984761927103140651">"প্ৰতিটো লগ বাফাৰত ৪মি."</item>
-    <item msgid="7892098981256010498">"প্ৰতিটো লগ বাফাৰত ১৬মি."</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"অফ অৱস্থাত আছে"</item>
     <item msgid="6014837961827347618">"সকলো"</item>
diff --git a/packages/SettingsLib/res/values-az/arrays.xml b/packages/SettingsLib/res/values-az/arrays.xml
index 55ec9d8..6ee2b8f 100644
--- a/packages/SettingsLib/res/values-az/arrays.xml
+++ b/packages/SettingsLib/res/values-az/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", aktiv (media)"</item>
     <item msgid="5001852592115448348">", aktiv (telefon)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Deaktiv"</item>
-    <item msgid="7839165897132179888">"64K"</item>
-    <item msgid="2715700596495505626">"256K"</item>
-    <item msgid="7099386891713159947">"1M"</item>
-    <item msgid="6069075827077845520">"4M"</item>
-    <item msgid="8243549501764402572">"16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Deaktiv"</item>
     <item msgid="4064786181089783077">"64K"</item>
     <item msgid="3052710745383602630">"256K"</item>
     <item msgid="3691785423374588514">"1M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Deaktiv"</item>
-    <item msgid="4195153527464162486">"hər jurnal buferinə 64K"</item>
-    <item msgid="7464037639415220106">"hər jurnal buferinə 256K"</item>
-    <item msgid="8539423820514360724">"hər jurnal buferinə 1M"</item>
-    <item msgid="1984761927103140651">"hər jurnal buferinə 4M"</item>
-    <item msgid="7892098981256010498">"hər jurnal buferinə 16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Deaktiv"</item>
     <item msgid="6014837961827347618">"Bütün"</item>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml b/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml
index 2926067..630ad7d 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", aktivan (medijski)"</item>
     <item msgid="5001852592115448348">", aktivan (telefon)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Isključeno"</item>
-    <item msgid="7839165897132179888">"64 kB"</item>
-    <item msgid="2715700596495505626">"256 kB"</item>
-    <item msgid="7099386891713159947">"1 MB"</item>
-    <item msgid="6069075827077845520">"4 MB"</item>
-    <item msgid="8243549501764402572">"16 MB"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Isključeno"</item>
     <item msgid="4064786181089783077">"64 kB"</item>
     <item msgid="3052710745383602630">"256 kB"</item>
     <item msgid="3691785423374588514">"1 MB"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Isključeno"</item>
-    <item msgid="4195153527464162486">"64 kB po međumemoriji evidencije"</item>
-    <item msgid="7464037639415220106">"256 kB po međumemoriji evidencije"</item>
-    <item msgid="8539423820514360724">"1 MB po međumemoriji evidencije"</item>
-    <item msgid="1984761927103140651">"4 MB po međumemoriji evidencije"</item>
-    <item msgid="7892098981256010498">"16 MB po međumemoriji evidencije"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Isključeno"</item>
     <item msgid="6014837961827347618">"Sve"</item>
diff --git a/packages/SettingsLib/res/values-be/arrays.xml b/packages/SettingsLib/res/values-be/arrays.xml
index af3a161..2d2c509 100644
--- a/packages/SettingsLib/res/values-be/arrays.xml
+++ b/packages/SettingsLib/res/values-be/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", уключана (мультымедыя)"</item>
     <item msgid="5001852592115448348">", уключана (тэлефон)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Выкл."</item>
-    <item msgid="7839165897132179888">"64K"</item>
-    <item msgid="2715700596495505626">"256K"</item>
-    <item msgid="7099386891713159947">"1M"</item>
-    <item msgid="6069075827077845520">"4M"</item>
-    <item msgid="8243549501764402572">"16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Выкл."</item>
     <item msgid="4064786181089783077">"64K"</item>
     <item msgid="3052710745383602630">"256K"</item>
     <item msgid="3691785423374588514">"1M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Выкл."</item>
-    <item msgid="4195153527464162486">"64K на буфер журнала"</item>
-    <item msgid="7464037639415220106">"256K на буфер журнала"</item>
-    <item msgid="8539423820514360724">"1M на буфер журнала"</item>
-    <item msgid="1984761927103140651">"4M на буфер журнала"</item>
-    <item msgid="7892098981256010498">"16M на буфер журнала"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Выключана"</item>
     <item msgid="6014837961827347618">"Усе"</item>
diff --git a/packages/SettingsLib/res/values-bg/arrays.xml b/packages/SettingsLib/res/values-bg/arrays.xml
index 1b25bed..482ec22 100644
--- a/packages/SettingsLib/res/values-bg/arrays.xml
+++ b/packages/SettingsLib/res/values-bg/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">"– активно (мултимедия)"</item>
     <item msgid="5001852592115448348">"– активно (телефон)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Изключено"</item>
-    <item msgid="7839165897132179888">"64 КБ"</item>
-    <item msgid="2715700596495505626">"256 КБ"</item>
-    <item msgid="7099386891713159947">"1 МБ"</item>
-    <item msgid="6069075827077845520">"4 МБ"</item>
-    <item msgid="8243549501764402572">"16 МБ"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Изключено"</item>
     <item msgid="4064786181089783077">"64 КБ"</item>
     <item msgid="3052710745383602630">"256 КБ"</item>
     <item msgid="3691785423374588514">"1 МБ"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Изключено"</item>
-    <item msgid="4195153527464162486">"Рег. буфер – 64 КБ"</item>
-    <item msgid="7464037639415220106">"Рег. буфер – 256 КБ"</item>
-    <item msgid="8539423820514360724">"Рег. буфер – 1 МБ"</item>
-    <item msgid="1984761927103140651">"Рег. буфер – 4 МБ"</item>
-    <item msgid="7892098981256010498">"Рег. буфер – 16 МБ"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Изкл."</item>
     <item msgid="6014837961827347618">"Всички"</item>
diff --git a/packages/SettingsLib/res/values-bn/arrays.xml b/packages/SettingsLib/res/values-bn/arrays.xml
index 34cbc8f..2da3076 100644
--- a/packages/SettingsLib/res/values-bn/arrays.xml
+++ b/packages/SettingsLib/res/values-bn/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", চালু আছে (মিডিয়া)"</item>
     <item msgid="5001852592115448348">", চালু আছে (ফোন)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"বন্ধ আছে"</item>
-    <item msgid="7839165897132179888">"৬৪K"</item>
-    <item msgid="2715700596495505626">"২৫৬K"</item>
-    <item msgid="7099386891713159947">"১M"</item>
-    <item msgid="6069075827077845520">"৪M"</item>
-    <item msgid="8243549501764402572">"১৬M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"বন্ধ আছে"</item>
     <item msgid="4064786181089783077">"৬৪K"</item>
     <item msgid="3052710745383602630">"২৫৬K"</item>
     <item msgid="3691785423374588514">"১M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"বন্ধ আছে"</item>
-    <item msgid="4195153527464162486">"লগ বাফার প্রতি ৬৪K"</item>
-    <item msgid="7464037639415220106">"লগ বাফার প্রতি ২৫৬K"</item>
-    <item msgid="8539423820514360724">"লগ বাফার প্রতি ১M"</item>
-    <item msgid="1984761927103140651">"লগ বাফার প্রতি ৪M"</item>
-    <item msgid="7892098981256010498">"লগ বাফার প্রতি ১৬M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"বন্ধ আছে"</item>
     <item msgid="6014837961827347618">"সমস্ত"</item>
diff --git a/packages/SettingsLib/res/values-bs/arrays.xml b/packages/SettingsLib/res/values-bs/arrays.xml
index 6d2f1f3..b704385 100644
--- a/packages/SettingsLib/res/values-bs/arrays.xml
+++ b/packages/SettingsLib/res/values-bs/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", aktivan (mediji)"</item>
     <item msgid="5001852592115448348">", aktivan (telefon)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Isključeno"</item>
-    <item msgid="7839165897132179888">"64K"</item>
-    <item msgid="2715700596495505626">"256K"</item>
-    <item msgid="7099386891713159947">"1M"</item>
-    <item msgid="6069075827077845520">"4M"</item>
-    <item msgid="8243549501764402572">"16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Isključeno"</item>
     <item msgid="4064786181089783077">"64K"</item>
     <item msgid="3052710745383602630">"256K"</item>
     <item msgid="3691785423374588514">"1M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Isključeno"</item>
-    <item msgid="4195153527464162486">"64K po međumemoriji zapisnika"</item>
-    <item msgid="7464037639415220106">"256k po međumemoriji zapisnika"</item>
-    <item msgid="8539423820514360724">"1M po međumemoriji zapisnika"</item>
-    <item msgid="1984761927103140651">"4M po međumemoriji zapisnika"</item>
-    <item msgid="7892098981256010498">"16M po međumemoriji zapisnika"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Isključeno"</item>
     <item msgid="6014837961827347618">"Sve"</item>
diff --git a/packages/SettingsLib/res/values-ca/arrays.xml b/packages/SettingsLib/res/values-ca/arrays.xml
index 4b24637..c9f63ab 100644
--- a/packages/SettingsLib/res/values-ca/arrays.xml
+++ b/packages/SettingsLib/res/values-ca/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", actiu (contingut multimèdia)"</item>
     <item msgid="5001852592115448348">", actiu (telèfon)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"No"</item>
-    <item msgid="7839165897132179888">"64 K"</item>
-    <item msgid="2715700596495505626">"256 K"</item>
-    <item msgid="7099386891713159947">"1 M"</item>
-    <item msgid="6069075827077845520">"4 M"</item>
-    <item msgid="8243549501764402572">"16 M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"No"</item>
     <item msgid="4064786181089783077">"64 K"</item>
     <item msgid="3052710745383602630">"256 K"</item>
     <item msgid="3691785423374588514">"1 M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"No"</item>
-    <item msgid="4195153527464162486">"64 K / memòria intermèdia del registre"</item>
-    <item msgid="7464037639415220106">"256 K / memòria intermèdia del registre"</item>
-    <item msgid="8539423820514360724">"1 M / memòria intermèdia reg."</item>
-    <item msgid="1984761927103140651">"4 M / memòria intermèdia del registre"</item>
-    <item msgid="7892098981256010498">"16 M / memòria intermèdia del registre"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Desactivat"</item>
     <item msgid="6014837961827347618">"Tot"</item>
diff --git a/packages/SettingsLib/res/values-cs/arrays.xml b/packages/SettingsLib/res/values-cs/arrays.xml
index 27dce16..556fc10 100644
--- a/packages/SettingsLib/res/values-cs/arrays.xml
+++ b/packages/SettingsLib/res/values-cs/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", aktivní (média)"</item>
     <item msgid="5001852592115448348">", aktivní (telefon)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Vypnuto"</item>
-    <item msgid="7839165897132179888">"64 kB"</item>
-    <item msgid="2715700596495505626">"256 kB"</item>
-    <item msgid="7099386891713159947">"1 MB"</item>
-    <item msgid="6069075827077845520">"4 MB"</item>
-    <item msgid="8243549501764402572">"16 MB"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Vypnuto"</item>
     <item msgid="4064786181089783077">"64 kB"</item>
     <item msgid="3052710745383602630">"256 kB"</item>
     <item msgid="3691785423374588514">"1 MB"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Vypnuto"</item>
-    <item msgid="4195153527464162486">"64 kB na vyrovnávací paměť protokolů"</item>
-    <item msgid="7464037639415220106">"256 kB na vyrovnávací paměť protokolů"</item>
-    <item msgid="8539423820514360724">"1 MB na vyrovnávací paměť protokolů"</item>
-    <item msgid="1984761927103140651">"4 MB na vyrovnávací paměť protokolů"</item>
-    <item msgid="7892098981256010498">"16 MB na vyrovnávací paměť protokolů"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Vypnuto"</item>
     <item msgid="6014837961827347618">"Vše"</item>
diff --git a/packages/SettingsLib/res/values-da/arrays.xml b/packages/SettingsLib/res/values-da/arrays.xml
index efe4150..69b8a09 100644
--- a/packages/SettingsLib/res/values-da/arrays.xml
+++ b/packages/SettingsLib/res/values-da/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", aktiv (medier)"</item>
     <item msgid="5001852592115448348">", aktiv (telefon)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Fra"</item>
-    <item msgid="7839165897132179888">"64 kB"</item>
-    <item msgid="2715700596495505626">"256 kB"</item>
-    <item msgid="7099386891713159947">"1 MB"</item>
-    <item msgid="6069075827077845520">"4 MB"</item>
-    <item msgid="8243549501764402572">"16 MB"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Fra"</item>
     <item msgid="4064786181089783077">"64 kB"</item>
     <item msgid="3052710745383602630">"256 kB"</item>
     <item msgid="3691785423374588514">"1 MB"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Fra"</item>
-    <item msgid="4195153527464162486">"64 kB pr. logbuffer"</item>
-    <item msgid="7464037639415220106">"256 kB pr. logbuffer"</item>
-    <item msgid="8539423820514360724">"1 MB pr. logbuffer"</item>
-    <item msgid="1984761927103140651">"4 MB pr. logbuffer"</item>
-    <item msgid="7892098981256010498">"16 MB pr. logbuffer"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Fra"</item>
     <item msgid="6014837961827347618">"Alle"</item>
diff --git a/packages/SettingsLib/res/values-de/arrays.xml b/packages/SettingsLib/res/values-de/arrays.xml
index e7c4887..f6e3496 100644
--- a/packages/SettingsLib/res/values-de/arrays.xml
+++ b/packages/SettingsLib/res/values-de/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", aktiv (Medien)"</item>
     <item msgid="5001852592115448348">", aktiv (Telefon)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Aus"</item>
-    <item msgid="7839165897132179888">"64.000"</item>
-    <item msgid="2715700596495505626">"256.000"</item>
-    <item msgid="7099386891713159947">"1 Mio."</item>
-    <item msgid="6069075827077845520">"4 Mio."</item>
-    <item msgid="8243549501764402572">"16 Mio."</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Aus"</item>
     <item msgid="4064786181089783077">"64.000"</item>
     <item msgid="3052710745383602630">"256.000"</item>
     <item msgid="3691785423374588514">"1 Mio."</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Aus"</item>
-    <item msgid="4195153527464162486">"64.000 pro Puffer"</item>
-    <item msgid="7464037639415220106">"256.000 pro Puffer"</item>
-    <item msgid="8539423820514360724">"1 Mio. pro Puffer"</item>
-    <item msgid="1984761927103140651">"4 Mio. pro Puffer"</item>
-    <item msgid="7892098981256010498">"16 Mio. pro Puffer"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Aus"</item>
     <item msgid="6014837961827347618">"Alle"</item>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 16af032..ba760dd 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -576,8 +576,7 @@
     <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
     <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
-    <!-- no translation found for data_connection_carrier_wifi (2250268321065848954) -->
-    <skip />
+    <string name="data_connection_carrier_wifi" msgid="2250268321065848954">"CWF"</string>
     <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobile Daten deaktiviert"</string>
     <string name="not_default_data_content_description" msgid="6517068332106592887">"Nicht für Datennutzung konfiguriert"</string>
     <string name="accessibility_no_phone" msgid="2687419663127582503">"Kein Telefon"</string>
diff --git a/packages/SettingsLib/res/values-el/arrays.xml b/packages/SettingsLib/res/values-el/arrays.xml
index 838ca79..2fc7d0b 100644
--- a/packages/SettingsLib/res/values-el/arrays.xml
+++ b/packages/SettingsLib/res/values-el/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", ενεργή (μέσα)"</item>
     <item msgid="5001852592115448348">", ενεργή (τηλέφωνο)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Ανενεργό"</item>
-    <item msgid="7839165897132179888">"64 K"</item>
-    <item msgid="2715700596495505626">"256 K"</item>
-    <item msgid="7099386891713159947">"1 M"</item>
-    <item msgid="6069075827077845520">"4 M"</item>
-    <item msgid="8243549501764402572">"16 M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Ανενεργό"</item>
     <item msgid="4064786181089783077">"64 K"</item>
     <item msgid="3052710745383602630">"256 K"</item>
     <item msgid="3691785423374588514">"1 M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Ανενεργό"</item>
-    <item msgid="4195153527464162486">"64 K ανά πρ. μν. αρχ. καταγρ."</item>
-    <item msgid="7464037639415220106">"256 K ανά πρ. μν. αρχ. καταγρ."</item>
-    <item msgid="8539423820514360724">"1 Μ ανά προσ. μν. αρχ. καταγρ."</item>
-    <item msgid="1984761927103140651">"4 M ανά προσ. μν. αρχ. καταγρ."</item>
-    <item msgid="7892098981256010498">"16 M ανά πρ. μν. αρχ. καταγρ."</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Ανενεργό"</item>
     <item msgid="6014837961827347618">"Όλα"</item>
diff --git a/packages/SettingsLib/res/values-en-rAU/arrays.xml b/packages/SettingsLib/res/values-en-rAU/arrays.xml
index 6569f18..31dc7c9 100644
--- a/packages/SettingsLib/res/values-en-rAU/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rAU/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", active (media)"</item>
     <item msgid="5001852592115448348">", active (phone)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Off"</item>
-    <item msgid="7839165897132179888">"64 K"</item>
-    <item msgid="2715700596495505626">"256 K"</item>
-    <item msgid="7099386891713159947">"1 M"</item>
-    <item msgid="6069075827077845520">"4 M"</item>
-    <item msgid="8243549501764402572">"16 M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Off"</item>
     <item msgid="4064786181089783077">"64 K"</item>
     <item msgid="3052710745383602630">"256 K"</item>
     <item msgid="3691785423374588514">"1 M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Off"</item>
-    <item msgid="4195153527464162486">"64 K per log buffer"</item>
-    <item msgid="7464037639415220106">"256 K per log buffer"</item>
-    <item msgid="8539423820514360724">"1 M per log buffer"</item>
-    <item msgid="1984761927103140651">"4 M per log buffer"</item>
-    <item msgid="7892098981256010498">"16 M per log buffer"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Off"</item>
     <item msgid="6014837961827347618">"All"</item>
diff --git a/packages/SettingsLib/res/values-en-rCA/arrays.xml b/packages/SettingsLib/res/values-en-rCA/arrays.xml
index 6569f18..31dc7c9 100644
--- a/packages/SettingsLib/res/values-en-rCA/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rCA/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", active (media)"</item>
     <item msgid="5001852592115448348">", active (phone)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Off"</item>
-    <item msgid="7839165897132179888">"64 K"</item>
-    <item msgid="2715700596495505626">"256 K"</item>
-    <item msgid="7099386891713159947">"1 M"</item>
-    <item msgid="6069075827077845520">"4 M"</item>
-    <item msgid="8243549501764402572">"16 M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Off"</item>
     <item msgid="4064786181089783077">"64 K"</item>
     <item msgid="3052710745383602630">"256 K"</item>
     <item msgid="3691785423374588514">"1 M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Off"</item>
-    <item msgid="4195153527464162486">"64 K per log buffer"</item>
-    <item msgid="7464037639415220106">"256 K per log buffer"</item>
-    <item msgid="8539423820514360724">"1 M per log buffer"</item>
-    <item msgid="1984761927103140651">"4 M per log buffer"</item>
-    <item msgid="7892098981256010498">"16 M per log buffer"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Off"</item>
     <item msgid="6014837961827347618">"All"</item>
diff --git a/packages/SettingsLib/res/values-en-rGB/arrays.xml b/packages/SettingsLib/res/values-en-rGB/arrays.xml
index 6569f18..31dc7c9 100644
--- a/packages/SettingsLib/res/values-en-rGB/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rGB/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", active (media)"</item>
     <item msgid="5001852592115448348">", active (phone)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Off"</item>
-    <item msgid="7839165897132179888">"64 K"</item>
-    <item msgid="2715700596495505626">"256 K"</item>
-    <item msgid="7099386891713159947">"1 M"</item>
-    <item msgid="6069075827077845520">"4 M"</item>
-    <item msgid="8243549501764402572">"16 M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Off"</item>
     <item msgid="4064786181089783077">"64 K"</item>
     <item msgid="3052710745383602630">"256 K"</item>
     <item msgid="3691785423374588514">"1 M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Off"</item>
-    <item msgid="4195153527464162486">"64 K per log buffer"</item>
-    <item msgid="7464037639415220106">"256 K per log buffer"</item>
-    <item msgid="8539423820514360724">"1 M per log buffer"</item>
-    <item msgid="1984761927103140651">"4 M per log buffer"</item>
-    <item msgid="7892098981256010498">"16 M per log buffer"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Off"</item>
     <item msgid="6014837961827347618">"All"</item>
diff --git a/packages/SettingsLib/res/values-en-rIN/arrays.xml b/packages/SettingsLib/res/values-en-rIN/arrays.xml
index 6569f18..31dc7c9 100644
--- a/packages/SettingsLib/res/values-en-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rIN/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", active (media)"</item>
     <item msgid="5001852592115448348">", active (phone)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Off"</item>
-    <item msgid="7839165897132179888">"64 K"</item>
-    <item msgid="2715700596495505626">"256 K"</item>
-    <item msgid="7099386891713159947">"1 M"</item>
-    <item msgid="6069075827077845520">"4 M"</item>
-    <item msgid="8243549501764402572">"16 M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Off"</item>
     <item msgid="4064786181089783077">"64 K"</item>
     <item msgid="3052710745383602630">"256 K"</item>
     <item msgid="3691785423374588514">"1 M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Off"</item>
-    <item msgid="4195153527464162486">"64 K per log buffer"</item>
-    <item msgid="7464037639415220106">"256 K per log buffer"</item>
-    <item msgid="8539423820514360724">"1 M per log buffer"</item>
-    <item msgid="1984761927103140651">"4 M per log buffer"</item>
-    <item msgid="7892098981256010498">"16 M per log buffer"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Off"</item>
     <item msgid="6014837961827347618">"All"</item>
diff --git a/packages/SettingsLib/res/values-en-rXC/arrays.xml b/packages/SettingsLib/res/values-en-rXC/arrays.xml
index cb702fe..e4322b9 100644
--- a/packages/SettingsLib/res/values-en-rXC/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rXC/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‏‏‎‏‏‏‏‎‏‎‎‎‏‏‎‏‎‎‏‎‎‏‎‎‏‎‏‏‎‏‏‎‏‎‏‎‏‏‎‎‏‏‏‎‎‏‎, active (media)‎‏‎‎‏‎"</item>
     <item msgid="5001852592115448348">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‏‎‏‎‏‎‎‎‏‎‎‏‏‎‎‏‏‎‏‏‏‎‎‏‏‏‏‎‏‏‏‏‏‎‏‎‎‎‎‏‏‏‏‎‏‎‎‎‎‏‏‏‎‎‎, active (phone)‎‏‎‎‏‎"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‏‏‎‎‏‎‏‎‎‏‏‎‏‏‏‎‏‏‎‏‎‎‎‎‏‎‏‏‎‎‏‏‎‎‏‎‏‎‎‎‎‏‎‎Off‎‏‎‎‏‎"</item>
-    <item msgid="7839165897132179888">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‎‏‎‎‏‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‏‎‎‏‏‏‏‎‏‎‏‏‏‎‎‎‎‎‎‏‏‎‏‏‎‎‎‎‎64K‎‏‎‎‏‎"</item>
-    <item msgid="2715700596495505626">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‏‎‏‏‎‏‏‎‎‎‎‎‎‎‏‏‎‏‏‎‏‎‎‏‏‎‏‏‏‎‏‏‎‏‎‎‏‏‎‏‏‏‎‎‏‎‏‏‎‎‎‏‏‎‏‏‎‏‎‎256K‎‏‎‎‏‎"</item>
-    <item msgid="7099386891713159947">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‎‎‎‏‏‎‎‎‎‏‎‏‏‎‏‏‎‎‎‎‏‏‏‎‎‎‏‎‏‏‏‎‏‎‎‎‎‎‏‎‏‎‎‎‏‏‎‎‎‎‏‎‏‏‎1M‎‏‎‎‏‎"</item>
-    <item msgid="6069075827077845520">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‏‏‎‎‏‏‎‏‏‎‎‎‎‎‏‎‎‏‏‏‏‎‎‏‏‎‎‏‏‏‏‏‎‎‎‏‎‏‎‎‏‎‎‏‎‎‎‎‏‎‎‎‎‎4M‎‏‎‎‏‎"</item>
-    <item msgid="8243549501764402572">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‏‎‏‏‏‏‏‎‎‎‏‎‎‏‏‎‎‎‎‏‏‏‏‏‎‏‎‎‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‎‎16M‎‏‎‎‏‎"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‏‏‎‏‎‎‎‏‏‏‏‎‏‎‏‏‏‎‏‎‏‎‏‏‏‏‎‏‎‎‏‏‏‎‏‎‏‏‎‎‏‏‏‎‏‎Off‎‏‎‎‏‎"</item>
     <item msgid="4064786181089783077">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‎‏‎‎‏‎‎‎‎‎‏‎‏‎‏‏‏‏‏‏‎‏‏‎‏‏‎‏‏‏‏‎‎‎‏‎‏‏‏‏‎‏‏‎‏‎‎‏‎‎‏‎‏‎64K‎‏‎‎‏‎"</item>
     <item msgid="3052710745383602630">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‎‏‎‎‏‎‏‏‏‎‏‎‏‏‎‏‎‎‎‎‎‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‎‎‏‏‎‏‏‏‎‎‎‏‎‎‏‏‏‎‎‎‏‏‎‎256K‎‏‎‎‏‎"</item>
     <item msgid="3691785423374588514">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‏‎‏‏‏‏‎‏‏‎‏‏‎‏‎‎‏‎‎‎‎‏‎‏‏‎‏‏‎‎‏‏‎‏‎‏‎‎‎‏‏‎‏‎‎‏‏‎‎‎‏‎‎1M‎‏‎‎‏‎"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‏‏‎‏‏‎‏‎‏‏‎‏‏‏‏‎‎‏‎‏‎‏‏‏‏‏‎‎‏‎‎‏‎‏‎‏‎‎‎‎‎‎‏‎‏‎‎‎‎‎‏‏‏‎‎‎‎‏‎‏‎Off‎‏‎‎‏‎"</item>
-    <item msgid="4195153527464162486">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‏‎‎‎‏‏‏‎‎‎‎‎‏‎‏‏‎‏‏‏‏‎‏‎‎‎‎‎‎‎‎‏‏‎‏‎‏‏‏‎‏‎‎‏‏‏‎‏‎‎‏‎‏‏‎‏‏‎‎64K per log buffer‎‏‎‎‏‎"</item>
-    <item msgid="7464037639415220106">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‎‏‎‏‏‎‎‏‎‏‏‎‏‎‏‎‏‏‏‏‏‏‎‏‎‏‏‏‎‏‏‏‏‏‎‏‎‏‎‎‎‏‏‏‏‎‎‎‏‎‏‎‎256K per log buffer‎‏‎‎‏‎"</item>
-    <item msgid="8539423820514360724">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‏‎‎‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‎‏‎‎‎‎‎‏‎‎‎‏‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‏‎‎‎1M per log buffer‎‏‎‎‏‎"</item>
-    <item msgid="1984761927103140651">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‎‏‏‏‎‎‎‏‎‏‏‎‏‎‎‏‎‏‎‎‏‏‏‎‏‎‎‏‏‏‏‏‏‎‎‏‎‏‏‎‎‏‏‏‏‎‏‎‎‏‏‎‎‏‎‏‎‏‏‎4M per log buffer‎‏‎‎‏‎"</item>
-    <item msgid="7892098981256010498">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‎‏‏‎‎‏‎‏‏‏‏‎‎‎‏‏‎‏‎‏‏‎‎‏‎‏‎‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎‏‏‎‎‎‎‎‎‏‎‎16M per log buffer‎‏‎‎‏‎"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‎‎‏‏‏‎‎‎‏‏‏‏‎‏‎‏‎‏‏‏‏‎‎‎‏‎‎‎‎‏‎‏‎‎‏‎‏‏‏‎‏‏‎‏‏‏‏‎‎‎‎‏‎‎‎‏‏‏‎‎Off‎‏‎‎‏‎"</item>
     <item msgid="6014837961827347618">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‏‏‏‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‎‏‎‎‎‎‎‎‏‎‎‎‎‎‎‏‏‏‎‏‏‎‎‏‎‏‎‎‎‏‎‎All‎‏‎‎‏‎"</item>
diff --git a/packages/SettingsLib/res/values-es-rUS/arrays.xml b/packages/SettingsLib/res/values-es-rUS/arrays.xml
index cfce9b6..cf6ce2b 100644
--- a/packages/SettingsLib/res/values-es-rUS/arrays.xml
+++ b/packages/SettingsLib/res/values-es-rUS/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", activo (contenido multimedia)"</item>
     <item msgid="5001852592115448348">", activo (teléfono)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Desactivado"</item>
-    <item msgid="7839165897132179888">"64 K"</item>
-    <item msgid="2715700596495505626">"256 K"</item>
-    <item msgid="7099386891713159947">"1 M"</item>
-    <item msgid="6069075827077845520">"4 M"</item>
-    <item msgid="8243549501764402572">"16 M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Desactivado"</item>
     <item msgid="4064786181089783077">"64 K"</item>
     <item msgid="3052710745383602630">"256 K"</item>
     <item msgid="3691785423374588514">"1 M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Desactivado"</item>
-    <item msgid="4195153527464162486">"64 K/búfer registro"</item>
-    <item msgid="7464037639415220106">"256 K/búfer registro"</item>
-    <item msgid="8539423820514360724">"1 M/búfer registro"</item>
-    <item msgid="1984761927103140651">"4 M/búfer registro"</item>
-    <item msgid="7892098981256010498">"16 M/búfer registro"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Desactivado"</item>
     <item msgid="6014837961827347618">"Todo"</item>
diff --git a/packages/SettingsLib/res/values-es/arrays.xml b/packages/SettingsLib/res/values-es/arrays.xml
index 5682dd5..37f91b2 100644
--- a/packages/SettingsLib/res/values-es/arrays.xml
+++ b/packages/SettingsLib/res/values-es/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", activo (contenido multimedia)"</item>
     <item msgid="5001852592115448348">", activo (teléfono)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Desactivado"</item>
-    <item msgid="7839165897132179888">"64 K"</item>
-    <item msgid="2715700596495505626">"256 K"</item>
-    <item msgid="7099386891713159947">"1 M"</item>
-    <item msgid="6069075827077845520">"4 M"</item>
-    <item msgid="8243549501764402572">"16 M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Desactivado"</item>
     <item msgid="4064786181089783077">"64 K"</item>
     <item msgid="3052710745383602630">"256 K"</item>
     <item msgid="3691785423374588514">"1 M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Desactivado"</item>
-    <item msgid="4195153527464162486">"64 K/búfer registro"</item>
-    <item msgid="7464037639415220106">"256 K/búfer registro"</item>
-    <item msgid="8539423820514360724">"1 M/búfer registro"</item>
-    <item msgid="1984761927103140651">"4 M/búfer registro"</item>
-    <item msgid="7892098981256010498">"16 M/búfer registro"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Desactivado"</item>
     <item msgid="6014837961827347618">"Todo"</item>
diff --git a/packages/SettingsLib/res/values-et/arrays.xml b/packages/SettingsLib/res/values-et/arrays.xml
index 9015cfe..537ea7a 100644
--- a/packages/SettingsLib/res/values-et/arrays.xml
+++ b/packages/SettingsLib/res/values-et/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", aktiivne (meedia)"</item>
     <item msgid="5001852592115448348">", aktiivne (telefon)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Väljas"</item>
-    <item msgid="7839165897132179888">"64 000"</item>
-    <item msgid="2715700596495505626">"256 000"</item>
-    <item msgid="7099386891713159947">"1 000 000"</item>
-    <item msgid="6069075827077845520">"4 000 000"</item>
-    <item msgid="8243549501764402572">"16 000 000"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Väljas"</item>
     <item msgid="4064786181089783077">"64 000"</item>
     <item msgid="3052710745383602630">"256 000"</item>
     <item msgid="3691785423374588514">"1 000 000"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Väljas"</item>
-    <item msgid="4195153527464162486">"64 000 / logipuhver"</item>
-    <item msgid="7464037639415220106">"256 000 / logipuhver"</item>
-    <item msgid="8539423820514360724">"1 000 000 / logipuhver"</item>
-    <item msgid="1984761927103140651">"4 000 000 / logipuhver"</item>
-    <item msgid="7892098981256010498">"16 000 000 / logipuhver"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Väljas"</item>
     <item msgid="6014837961827347618">"Kõik"</item>
diff --git a/packages/SettingsLib/res/values-eu/arrays.xml b/packages/SettingsLib/res/values-eu/arrays.xml
index 0e94bba..367d31c 100644
--- a/packages/SettingsLib/res/values-eu/arrays.xml
+++ b/packages/SettingsLib/res/values-eu/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", aktibo (multimedia-edukia)"</item>
     <item msgid="5001852592115448348">", aktibo (telefonoa)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Desaktibatuta"</item>
-    <item msgid="7839165897132179888">"64 K"</item>
-    <item msgid="2715700596495505626">"256 K"</item>
-    <item msgid="7099386891713159947">"1 M"</item>
-    <item msgid="6069075827077845520">"4 M"</item>
-    <item msgid="8243549501764402572">"16 M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Desaktibatuta"</item>
     <item msgid="4064786181089783077">"64 K"</item>
     <item msgid="3052710745383602630">"256 K"</item>
     <item msgid="3691785423374588514">"1 M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Desaktibatuta"</item>
-    <item msgid="4195153527464162486">"64 K erregistroen bufferreko"</item>
-    <item msgid="7464037639415220106">"256 K erregistroen bufferreko"</item>
-    <item msgid="8539423820514360724">"1 M erregistroen bufferreko"</item>
-    <item msgid="1984761927103140651">"4 M erregistroen bufferreko"</item>
-    <item msgid="7892098981256010498">"16 M erregistroen bufferreko"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Desaktibatuta"</item>
     <item msgid="6014837961827347618">"Guztiak"</item>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index c7b376a..2582854 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -576,8 +576,7 @@
     <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
     <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
-    <!-- no translation found for data_connection_carrier_wifi (2250268321065848954) -->
-    <skip />
+    <string name="data_connection_carrier_wifi" msgid="2250268321065848954">"CWF"</string>
     <string name="cell_data_off_content_description" msgid="2280700839891636498">"Desaktibatuta dago datu-konexioa"</string>
     <string name="not_default_data_content_description" msgid="6517068332106592887">"Ez dago ezarrita datuak erabiltzeko"</string>
     <string name="accessibility_no_phone" msgid="2687419663127582503">"Ez dago telefono-zenbakirik."</string>
diff --git a/packages/SettingsLib/res/values-fa/arrays.xml b/packages/SettingsLib/res/values-fa/arrays.xml
index 075f7e0..070c8ec 100644
--- a/packages/SettingsLib/res/values-fa/arrays.xml
+++ b/packages/SettingsLib/res/values-fa/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">"، فعال (رسانه)"</item>
     <item msgid="5001852592115448348">"، فعال (تلفن)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"خاموش"</item>
-    <item msgid="7839165897132179888">"۶۴ هزار"</item>
-    <item msgid="2715700596495505626">"۲۵۶ هزار"</item>
-    <item msgid="7099386891713159947">"۱ میلیون"</item>
-    <item msgid="6069075827077845520">"۴ میلیون"</item>
-    <item msgid="8243549501764402572">"۱۶ میلیون"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"خاموش"</item>
     <item msgid="4064786181089783077">"۶۴ هزار"</item>
     <item msgid="3052710745383602630">"۲۵۶ هزار"</item>
     <item msgid="3691785423374588514">"۱ میلیون"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"خاموش"</item>
-    <item msgid="4195153527464162486">"۶۴ هزار در هر بافر گزارش"</item>
-    <item msgid="7464037639415220106">"۲۵۶ هزار در هر بافر گزارش"</item>
-    <item msgid="8539423820514360724">"۱ میلیون در هر بافر گزارش"</item>
-    <item msgid="1984761927103140651">"۴ میلیون در هر بافر گزارش"</item>
-    <item msgid="7892098981256010498">"۱۶ میلیون در هر بافر گزارش"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"خاموش"</item>
     <item msgid="6014837961827347618">"همه"</item>
diff --git a/packages/SettingsLib/res/values-fi/arrays.xml b/packages/SettingsLib/res/values-fi/arrays.xml
index d233c56..6c38cdf 100644
--- a/packages/SettingsLib/res/values-fi/arrays.xml
+++ b/packages/SettingsLib/res/values-fi/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", aktiivinen (media)"</item>
     <item msgid="5001852592115448348">", aktiivinen (puhelin)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Ei päällä"</item>
-    <item msgid="7839165897132179888">"64 kt"</item>
-    <item msgid="2715700596495505626">"256 kt"</item>
-    <item msgid="7099386891713159947">"1 Mt"</item>
-    <item msgid="6069075827077845520">"4 Mt"</item>
-    <item msgid="8243549501764402572">"16 Mt"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Ei päällä"</item>
     <item msgid="4064786181089783077">"64 kt"</item>
     <item msgid="3052710745383602630">"256 kt"</item>
     <item msgid="3691785423374588514">"1 Mt"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Ei päällä"</item>
-    <item msgid="4195153527464162486">"64 kt / lokipuskuri"</item>
-    <item msgid="7464037639415220106">"256 kt / lokipuskuri"</item>
-    <item msgid="8539423820514360724">"1 Mt / lokipuskuri"</item>
-    <item msgid="1984761927103140651">"4 Mt / lokipuskuri"</item>
-    <item msgid="7892098981256010498">"16 Mt / lokipuskuri"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Ei päällä"</item>
     <item msgid="6014837961827347618">"Kaikki"</item>
diff --git a/packages/SettingsLib/res/values-fr-rCA/arrays.xml b/packages/SettingsLib/res/values-fr-rCA/arrays.xml
index 1db6540..8d48047 100644
--- a/packages/SettingsLib/res/values-fr-rCA/arrays.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", actif (média)"</item>
     <item msgid="5001852592115448348">", actif (téléphone)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Désactivé"</item>
-    <item msgid="7839165897132179888">"64 ko"</item>
-    <item msgid="2715700596495505626">"256 ko"</item>
-    <item msgid="7099386891713159947">"1 Mo"</item>
-    <item msgid="6069075827077845520">"4 Mo"</item>
-    <item msgid="8243549501764402572">"16 Mo"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Désactivé"</item>
     <item msgid="4064786181089783077">"64 ko"</item>
     <item msgid="3052710745383602630">"256 ko"</item>
     <item msgid="3691785423374588514">"1 Mo"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Désactivé"</item>
-    <item msgid="4195153527464162486">"64 ko/tampon journal"</item>
-    <item msgid="7464037639415220106">"256 Ko/tampon journal"</item>
-    <item msgid="8539423820514360724">"1 Mo/tampon journal"</item>
-    <item msgid="1984761927103140651">"4 Mo/tampon journal"</item>
-    <item msgid="7892098981256010498">"16 Mo/tampon journal"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Désactivé"</item>
     <item msgid="6014837961827347618">"Tous"</item>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 58ea795..e24c130 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -226,7 +226,7 @@
     <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Code d\'association Wi-Fi"</string>
     <string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Échec de l\'association"</string>
     <string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Vérifier que l\'appareil est connecté au même réseau."</string>
-    <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Associer un appareil par Wi-Fi en numérisant un code QR"</string>
+    <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Associez l\'appareil par Wi-Fi en numérisant un code QR"</string>
     <string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Association de l\'appareil en cours…"</string>
     <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Échec de l\'association de l\'appareil Soit le code QR est incorrect, soit l\'appareil n\'est pas connecté au même réseau."</string>
     <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Adresse IP et port"</string>
@@ -576,8 +576,7 @@
     <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
     <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
-    <!-- no translation found for data_connection_carrier_wifi (2250268321065848954) -->
-    <skip />
+    <string name="data_connection_carrier_wifi" msgid="2250268321065848954">"CWF"</string>
     <string name="cell_data_off_content_description" msgid="2280700839891636498">"Désactivées"</string>
     <string name="not_default_data_content_description" msgid="6517068332106592887">"Non configuré pour l\'utilisation des données cellulaires"</string>
     <string name="accessibility_no_phone" msgid="2687419663127582503">"Aucun signal"</string>
diff --git a/packages/SettingsLib/res/values-fr/arrays.xml b/packages/SettingsLib/res/values-fr/arrays.xml
index 7660925..d65ba69 100644
--- a/packages/SettingsLib/res/values-fr/arrays.xml
+++ b/packages/SettingsLib/res/values-fr/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", actif (son des médias)"</item>
     <item msgid="5001852592115448348">", actif (téléphone)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Désactivé"</item>
-    <item msgid="7839165897132179888">"64 Ko"</item>
-    <item msgid="2715700596495505626">"256 Ko"</item>
-    <item msgid="7099386891713159947">"1 Mo"</item>
-    <item msgid="6069075827077845520">"4 Mo"</item>
-    <item msgid="8243549501764402572">"16 Mo"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Désactivé"</item>
     <item msgid="4064786181089783077">"64 Ko"</item>
     <item msgid="3052710745383602630">"256 Ko"</item>
     <item msgid="3691785423374588514">"1 Mo"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Désactivé"</item>
-    <item msgid="4195153527464162486">"64 Ko par tampon journal"</item>
-    <item msgid="7464037639415220106">"256 Ko par tampon journal"</item>
-    <item msgid="8539423820514360724">"1 Mo par tampon journal"</item>
-    <item msgid="1984761927103140651">"4 Mo par tampon journal"</item>
-    <item msgid="7892098981256010498">"16 Mo par tampon journal"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Désactivé"</item>
     <item msgid="6014837961827347618">"Tous"</item>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index f321ea3..a79ed0c 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -576,8 +576,7 @@
     <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
     <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
-    <!-- no translation found for data_connection_carrier_wifi (2250268321065848954) -->
-    <skip />
+    <string name="data_connection_carrier_wifi" msgid="2250268321065848954">"CWF"</string>
     <string name="cell_data_off_content_description" msgid="2280700839891636498">"Désactivées"</string>
     <string name="not_default_data_content_description" msgid="6517068332106592887">"Non configuré pour utiliser les données"</string>
     <string name="accessibility_no_phone" msgid="2687419663127582503">"Aucun signal"</string>
diff --git a/packages/SettingsLib/res/values-gl/arrays.xml b/packages/SettingsLib/res/values-gl/arrays.xml
index 98f2072..f13eaae 100644
--- a/packages/SettingsLib/res/values-gl/arrays.xml
+++ b/packages/SettingsLib/res/values-gl/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", activo (contido multimedia)"</item>
     <item msgid="5001852592115448348">", activo (teléfono)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Desactivado"</item>
-    <item msgid="7839165897132179888">"64 K"</item>
-    <item msgid="2715700596495505626">"256 K"</item>
-    <item msgid="7099386891713159947">"1 M"</item>
-    <item msgid="6069075827077845520">"4 M"</item>
-    <item msgid="8243549501764402572">"16 M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Desactivado"</item>
     <item msgid="4064786181089783077">"64 K"</item>
     <item msgid="3052710745383602630">"256 K"</item>
     <item msgid="3691785423374588514">"1 M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Desactivado"</item>
-    <item msgid="4195153527464162486">"64 K por búfer de rexistro"</item>
-    <item msgid="7464037639415220106">"256 K por búfer de rexistro"</item>
-    <item msgid="8539423820514360724">"1 M por búfer de rexistro"</item>
-    <item msgid="1984761927103140651">"4 M por búfer de rexistro"</item>
-    <item msgid="7892098981256010498">"16 M por búfer de rexistro"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Desactivado"</item>
     <item msgid="6014837961827347618">"Todo"</item>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 254958f..97662a6 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -576,8 +576,7 @@
     <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
     <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
-    <!-- no translation found for data_connection_carrier_wifi (2250268321065848954) -->
-    <skip />
+    <string name="data_connection_carrier_wifi" msgid="2250268321065848954">"Operador de wifi"</string>
     <string name="cell_data_off_content_description" msgid="2280700839891636498">"Os datos móbiles están desactivados"</string>
     <string name="not_default_data_content_description" msgid="6517068332106592887">"Non se configurou para utilizar datos"</string>
     <string name="accessibility_no_phone" msgid="2687419663127582503">"Sen teléfono"</string>
diff --git a/packages/SettingsLib/res/values-gu/arrays.xml b/packages/SettingsLib/res/values-gu/arrays.xml
index 1a3bf98..0bbd4f6 100644
--- a/packages/SettingsLib/res/values-gu/arrays.xml
+++ b/packages/SettingsLib/res/values-gu/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", સક્રિય (મીડિયા)"</item>
     <item msgid="5001852592115448348">", સક્રિય (ફોન)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"બંધ"</item>
-    <item msgid="7839165897132179888">"64K"</item>
-    <item msgid="2715700596495505626">"256K"</item>
-    <item msgid="7099386891713159947">"1M"</item>
-    <item msgid="6069075827077845520">"4M"</item>
-    <item msgid="8243549501764402572">"16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"બંધ"</item>
     <item msgid="4064786181089783077">"64K"</item>
     <item msgid="3052710745383602630">"256K"</item>
     <item msgid="3691785423374588514">"1M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"બંધ"</item>
-    <item msgid="4195153527464162486">"લૉગ બફર દીઠ 64K"</item>
-    <item msgid="7464037639415220106">"લૉગ બફર દીઠ 256K"</item>
-    <item msgid="8539423820514360724">"લૉગ બફર દીઠ 1M"</item>
-    <item msgid="1984761927103140651">"લૉગ બફર દીઠ 4M"</item>
-    <item msgid="7892098981256010498">"લૉગ બફર દીઠ 16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"બંધ"</item>
     <item msgid="6014837961827347618">"તમામ"</item>
diff --git a/packages/SettingsLib/res/values-hi/arrays.xml b/packages/SettingsLib/res/values-hi/arrays.xml
index 36b16e6..ace8b4a 100644
--- a/packages/SettingsLib/res/values-hi/arrays.xml
+++ b/packages/SettingsLib/res/values-hi/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", चालू है (सिर्फ़ मीडिया के लिए)"</item>
     <item msgid="5001852592115448348">", चालू है (सिर्फ़ फ़ोन के लिए)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"बंद"</item>
-    <item msgid="7839165897132179888">"64K"</item>
-    <item msgid="2715700596495505626">"256K"</item>
-    <item msgid="7099386891713159947">"1M"</item>
-    <item msgid="6069075827077845520">"4M"</item>
-    <item msgid="8243549501764402572">"16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"बंद"</item>
     <item msgid="4064786181089783077">"64K"</item>
     <item msgid="3052710745383602630">"256K"</item>
     <item msgid="3691785423374588514">"1M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"बंद"</item>
-    <item msgid="4195153527464162486">"64K प्रति लॉग बफ़र"</item>
-    <item msgid="7464037639415220106">"256K प्रति लॉग बफ़र"</item>
-    <item msgid="8539423820514360724">"1 एमबी प्रति लॉग बफ़र"</item>
-    <item msgid="1984761927103140651">"4M प्रति लॉग बफ़र"</item>
-    <item msgid="7892098981256010498">"16M प्रति लॉग बफ़र"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"बंद"</item>
     <item msgid="6014837961827347618">"सभी"</item>
diff --git a/packages/SettingsLib/res/values-hr/arrays.xml b/packages/SettingsLib/res/values-hr/arrays.xml
index 82a1e4a..c4188bf 100644
--- a/packages/SettingsLib/res/values-hr/arrays.xml
+++ b/packages/SettingsLib/res/values-hr/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", aktivno (mediji)"</item>
     <item msgid="5001852592115448348">", aktivno (telefon)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Isključeno"</item>
-    <item msgid="7839165897132179888">"64 KB"</item>
-    <item msgid="2715700596495505626">"256 KB"</item>
-    <item msgid="7099386891713159947">"1 MB"</item>
-    <item msgid="6069075827077845520">"4 MB"</item>
-    <item msgid="8243549501764402572">"16 MB"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Isključeno"</item>
     <item msgid="4064786181089783077">"64 KB"</item>
     <item msgid="3052710745383602630">"256 KB"</item>
     <item msgid="3691785423374588514">"1 MB"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Isključeno"</item>
-    <item msgid="4195153527464162486">"64 KB po međusprem. zapisnika"</item>
-    <item msgid="7464037639415220106">"256 KB po međusprem. zapisnika"</item>
-    <item msgid="8539423820514360724">"1 MB po međusprem. zapisnika"</item>
-    <item msgid="1984761927103140651">"4 MB po međusprem. zapisnika"</item>
-    <item msgid="7892098981256010498">"16 MB po međusprem. zapisnika"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Isključeno"</item>
     <item msgid="6014837961827347618">"Sve"</item>
diff --git a/packages/SettingsLib/res/values-hu/arrays.xml b/packages/SettingsLib/res/values-hu/arrays.xml
index d043af0..cc36c18 100644
--- a/packages/SettingsLib/res/values-hu/arrays.xml
+++ b/packages/SettingsLib/res/values-hu/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", aktív (média)"</item>
     <item msgid="5001852592115448348">", aktív (telefon)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Ki"</item>
-    <item msgid="7839165897132179888">"64 KB"</item>
-    <item msgid="2715700596495505626">"256 KB"</item>
-    <item msgid="7099386891713159947">"1 MB"</item>
-    <item msgid="6069075827077845520">"4 MB"</item>
-    <item msgid="8243549501764402572">"16 MB"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Ki"</item>
     <item msgid="4064786181089783077">"64 KB"</item>
     <item msgid="3052710745383602630">"256 KB"</item>
     <item msgid="3691785423374588514">"1 MB"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Ki"</item>
-    <item msgid="4195153527464162486">"64 KB/naplópuffer"</item>
-    <item msgid="7464037639415220106">"256 KB/naplópuffer"</item>
-    <item msgid="8539423820514360724">"1 MB/naplópuffer"</item>
-    <item msgid="1984761927103140651">"4 MB/naplópuffer"</item>
-    <item msgid="7892098981256010498">"16 MB/naplópuffer"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Kikapcsolva"</item>
     <item msgid="6014837961827347618">"Összes"</item>
diff --git a/packages/SettingsLib/res/values-hy/arrays.xml b/packages/SettingsLib/res/values-hy/arrays.xml
index a279872..76ed9bd 100644
--- a/packages/SettingsLib/res/values-hy/arrays.xml
+++ b/packages/SettingsLib/res/values-hy/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", ակտիվ է (մեդիա)"</item>
     <item msgid="5001852592115448348">", ակտիվ է (հեռախոս)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Անջատված է"</item>
-    <item msgid="7839165897132179888">"64ԿԲ"</item>
-    <item msgid="2715700596495505626">"256ԿԲ"</item>
-    <item msgid="7099386891713159947">"1ՄԲ"</item>
-    <item msgid="6069075827077845520">"4ՄԲ"</item>
-    <item msgid="8243549501764402572">"16ՄԲ"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Անջատված է"</item>
     <item msgid="4064786181089783077">"64ԿԲ"</item>
     <item msgid="3052710745383602630">"256ԿԲ"</item>
     <item msgid="3691785423374588514">"1ՄԲ"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Անջատված է"</item>
-    <item msgid="4195153527464162486">"Բուֆեր՝ առավ. 64ԿԲ"</item>
-    <item msgid="7464037639415220106">"Բուֆեր՝ առավ. 256ԿԲ"</item>
-    <item msgid="8539423820514360724">"Բուֆեր՝ առավ. 1ՄԲ"</item>
-    <item msgid="1984761927103140651">"Բուֆեր՝ առավ. 4ՄԲ"</item>
-    <item msgid="7892098981256010498">"Բուֆեր՝ առավ. 16ՄԲ"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Անջատված է"</item>
     <item msgid="6014837961827347618">"Բոլորը"</item>
diff --git a/packages/SettingsLib/res/values-in/arrays.xml b/packages/SettingsLib/res/values-in/arrays.xml
index 3ab50cc..14e3313 100644
--- a/packages/SettingsLib/res/values-in/arrays.xml
+++ b/packages/SettingsLib/res/values-in/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", aktif (media)"</item>
     <item msgid="5001852592115448348">", aktif (ponsel)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Nonaktif"</item>
-    <item msgid="7839165897132179888">"64 K"</item>
-    <item msgid="2715700596495505626">"256 K"</item>
-    <item msgid="7099386891713159947">"1 M"</item>
-    <item msgid="6069075827077845520">"4 M"</item>
-    <item msgid="8243549501764402572">"16 M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Nonaktif"</item>
     <item msgid="4064786181089783077">"64 K"</item>
     <item msgid="3052710745383602630">"256 K"</item>
     <item msgid="3691785423374588514">"1 M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Nonaktif"</item>
-    <item msgid="4195153527464162486">"64 K/buffer log"</item>
-    <item msgid="7464037639415220106">"256 K/buffer log"</item>
-    <item msgid="8539423820514360724">"1 M/buffer log"</item>
-    <item msgid="1984761927103140651">"4 M/buffer log"</item>
-    <item msgid="7892098981256010498">"16 M/buffer log"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Nonaktif"</item>
     <item msgid="6014837961827347618">"Semua"</item>
diff --git a/packages/SettingsLib/res/values-is/arrays.xml b/packages/SettingsLib/res/values-is/arrays.xml
index 93274e4..7c1773b 100644
--- a/packages/SettingsLib/res/values-is/arrays.xml
+++ b/packages/SettingsLib/res/values-is/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", virkt (hljóð- og myndefni)"</item>
     <item msgid="5001852592115448348">", virkt (sími)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Slökkt"</item>
-    <item msgid="7839165897132179888">"64 k"</item>
-    <item msgid="2715700596495505626">"256 k"</item>
-    <item msgid="7099386891713159947">"1 M"</item>
-    <item msgid="6069075827077845520">"4 M"</item>
-    <item msgid="8243549501764402572">"16 M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Slökkt"</item>
     <item msgid="4064786181089783077">"64 k"</item>
     <item msgid="3052710745383602630">"256 k"</item>
     <item msgid="3691785423374588514">"1 M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Slökkt"</item>
-    <item msgid="4195153527464162486">"64 k/biðminni"</item>
-    <item msgid="7464037639415220106">"256 k/biðminni"</item>
-    <item msgid="8539423820514360724">"1 M/biðminni"</item>
-    <item msgid="1984761927103140651">"4 M/biðminni"</item>
-    <item msgid="7892098981256010498">"16 M/biðminni"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Slökkt"</item>
     <item msgid="6014837961827347618">"Allt"</item>
diff --git a/packages/SettingsLib/res/values-it/arrays.xml b/packages/SettingsLib/res/values-it/arrays.xml
index 57c0c9b..127903f 100644
--- a/packages/SettingsLib/res/values-it/arrays.xml
+++ b/packages/SettingsLib/res/values-it/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", attivo (contenuti multimediali)"</item>
     <item msgid="5001852592115448348">", attivo (telefono)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Off"</item>
-    <item msgid="7839165897132179888">"64 kB"</item>
-    <item msgid="2715700596495505626">"256 kB"</item>
-    <item msgid="7099386891713159947">"1 MB"</item>
-    <item msgid="6069075827077845520">"4 MB"</item>
-    <item msgid="8243549501764402572">"16 MB"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Off"</item>
     <item msgid="4064786181089783077">"64 kB"</item>
     <item msgid="3052710745383602630">"256 kB"</item>
     <item msgid="3691785423374588514">"1 MB"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Off"</item>
-    <item msgid="4195153527464162486">"64 kB/buffer log"</item>
-    <item msgid="7464037639415220106">"256 kB/buffer log"</item>
-    <item msgid="8539423820514360724">"1 MB/buffer log"</item>
-    <item msgid="1984761927103140651">"4 MB/buffer log"</item>
-    <item msgid="7892098981256010498">"16 MB/buffer log"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Off"</item>
     <item msgid="6014837961827347618">"Tutti"</item>
diff --git a/packages/SettingsLib/res/values-iw/arrays.xml b/packages/SettingsLib/res/values-iw/arrays.xml
index fa53ab8..151b825 100644
--- a/packages/SettingsLib/res/values-iw/arrays.xml
+++ b/packages/SettingsLib/res/values-iw/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", פעיל (מדיה)"</item>
     <item msgid="5001852592115448348">", פעיל (טלפון)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"כבוי"</item>
-    <item msgid="7839165897132179888">"64K"</item>
-    <item msgid="2715700596495505626">"‎256K"</item>
-    <item msgid="7099386891713159947">"1M"</item>
-    <item msgid="6069075827077845520">"4M"</item>
-    <item msgid="8243549501764402572">"16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"כבוי"</item>
     <item msgid="4064786181089783077">"64K"</item>
     <item msgid="3052710745383602630">"‎256K"</item>
     <item msgid="3691785423374588514">"1M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"כבוי"</item>
-    <item msgid="4195153527464162486">"‏64K לכל מאגר של יומן רישום"</item>
-    <item msgid="7464037639415220106">"‏256K לכל מאגר של יומן רישום"</item>
-    <item msgid="8539423820514360724">"‏1M לכל מאגר של יומן רישום"</item>
-    <item msgid="1984761927103140651">"‏4M לכל מאגר של יומן רישום"</item>
-    <item msgid="7892098981256010498">"‏16M לכל מאגר של יומן רישום"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"כבוי"</item>
     <item msgid="6014837961827347618">"הכול"</item>
diff --git a/packages/SettingsLib/res/values-ja/arrays.xml b/packages/SettingsLib/res/values-ja/arrays.xml
index 7a4e71b..1401069 100644
--- a/packages/SettingsLib/res/values-ja/arrays.xml
+++ b/packages/SettingsLib/res/values-ja/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">"、有効(メディア)"</item>
     <item msgid="5001852592115448348">"、有効(スマートフォン)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"OFF"</item>
-    <item msgid="7839165897132179888">"64 K"</item>
-    <item msgid="2715700596495505626">"256 K"</item>
-    <item msgid="7099386891713159947">"1 M"</item>
-    <item msgid="6069075827077845520">"4 M"</item>
-    <item msgid="8243549501764402572">"16 M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"OFF"</item>
     <item msgid="4064786181089783077">"64 K"</item>
     <item msgid="3052710745383602630">"256 K"</item>
     <item msgid="3691785423374588514">"1 M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"OFF"</item>
-    <item msgid="4195153527464162486">"64 K / ログバッファ"</item>
-    <item msgid="7464037639415220106">"256 K / ログバッファ"</item>
-    <item msgid="8539423820514360724">"1 M / ログバッファ"</item>
-    <item msgid="1984761927103140651">"4 M / ログバッファ"</item>
-    <item msgid="7892098981256010498">"16 M / ログバッファ"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"OFF"</item>
     <item msgid="6014837961827347618">"すべて"</item>
diff --git a/packages/SettingsLib/res/values-ka/arrays.xml b/packages/SettingsLib/res/values-ka/arrays.xml
index 935cc46..62ae1e6 100644
--- a/packages/SettingsLib/res/values-ka/arrays.xml
+++ b/packages/SettingsLib/res/values-ka/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", აქტიური (მედია)"</item>
     <item msgid="5001852592115448348">", აქტიური (ტელეფონი)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"გამორთული"</item>
-    <item msgid="7839165897132179888">"64 კბაიტი"</item>
-    <item msgid="2715700596495505626">"256 კბაიტი"</item>
-    <item msgid="7099386891713159947">"1 მბაიტი"</item>
-    <item msgid="6069075827077845520">"4 მბაიტი"</item>
-    <item msgid="8243549501764402572">"16 მბაიტი"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"გამორთული"</item>
     <item msgid="4064786181089783077">"64 კბაიტი"</item>
     <item msgid="3052710745383602630">"256 კბაიტი"</item>
     <item msgid="3691785423374588514">"1 მბაიტი"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"გამორთული"</item>
-    <item msgid="4195153527464162486">"64 კბაიტი / ჟურნალის ბუფერი"</item>
-    <item msgid="7464037639415220106">"256 კბაიტი / ჟურნალის ბუფერი"</item>
-    <item msgid="8539423820514360724">"1 მბაიტი / ჟურნალის ბუფერი"</item>
-    <item msgid="1984761927103140651">"4 მბაიტი / ჟურნალის ბუფერი"</item>
-    <item msgid="7892098981256010498">"16 მბაიტი / ჟურნალის ბუფერი"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"გამორთული"</item>
     <item msgid="6014837961827347618">"ყველა"</item>
diff --git a/packages/SettingsLib/res/values-kk/arrays.xml b/packages/SettingsLib/res/values-kk/arrays.xml
index faa8af8..a2fe014 100644
--- a/packages/SettingsLib/res/values-kk/arrays.xml
+++ b/packages/SettingsLib/res/values-kk/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", қосулы (медиамазмұн)"</item>
     <item msgid="5001852592115448348">", қосулы (телефон)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Өшірулі"</item>
-    <item msgid="7839165897132179888">"64 КБ"</item>
-    <item msgid="2715700596495505626">"256 КБ"</item>
-    <item msgid="7099386891713159947">"1 МБ"</item>
-    <item msgid="6069075827077845520">"4 МБ"</item>
-    <item msgid="8243549501764402572">"16 МБ"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Өшірулі"</item>
     <item msgid="4064786181089783077">"64 КБ"</item>
     <item msgid="3052710745383602630">"256 КБ"</item>
     <item msgid="3691785423374588514">"1 МБ"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Өшірулі"</item>
-    <item msgid="4195153527464162486">"Әр журнал буферіне 64 КБ"</item>
-    <item msgid="7464037639415220106">"Әр журнал буферіне 256 КБ"</item>
-    <item msgid="8539423820514360724">"Әр журнал буферіне 1 МБ"</item>
-    <item msgid="1984761927103140651">"Әр журнал буферіне 4 МБ"</item>
-    <item msgid="7892098981256010498">"Әр журнал буферіне 16 МБ"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Өшірулі"</item>
     <item msgid="6014837961827347618">"Барлығы"</item>
diff --git a/packages/SettingsLib/res/values-km/arrays.xml b/packages/SettingsLib/res/values-km/arrays.xml
index 6f4589e..70c1e33 100644
--- a/packages/SettingsLib/res/values-km/arrays.xml
+++ b/packages/SettingsLib/res/values-km/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">"សកម្ម (មេឌៀ)"</item>
     <item msgid="5001852592115448348">"សកម្ម (ទូរសព្ទ)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"បិទ"</item>
-    <item msgid="7839165897132179888">"64K"</item>
-    <item msgid="2715700596495505626">"256K"</item>
-    <item msgid="7099386891713159947">"1M"</item>
-    <item msgid="6069075827077845520">"4M"</item>
-    <item msgid="8243549501764402572">"16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"បិទ"</item>
     <item msgid="4064786181089783077">"64K"</item>
     <item msgid="3052710745383602630">"256K"</item>
     <item msgid="3691785423374588514">"1M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"បិទ"</item>
-    <item msgid="4195153527464162486">"64K per log buffer"</item>
-    <item msgid="7464037639415220106">"256K per log buffer"</item>
-    <item msgid="8539423820514360724">"1M per log buffer"</item>
-    <item msgid="1984761927103140651">"4M per log buffer"</item>
-    <item msgid="7892098981256010498">"16M per log buffer"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"បិទ"</item>
     <item msgid="6014837961827347618">"ទាំង​អស់"</item>
diff --git a/packages/SettingsLib/res/values-kn/arrays.xml b/packages/SettingsLib/res/values-kn/arrays.xml
index 7e543dd..1bfcdc0 100644
--- a/packages/SettingsLib/res/values-kn/arrays.xml
+++ b/packages/SettingsLib/res/values-kn/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", ಸಕ್ರಿಯ (ಮಾಧ್ಯಮ)"</item>
     <item msgid="5001852592115448348">", ಸಕ್ರಿಯ (ಫೋನ್)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"ಆಫ್"</item>
-    <item msgid="7839165897132179888">"64K"</item>
-    <item msgid="2715700596495505626">"256K"</item>
-    <item msgid="7099386891713159947">"1M"</item>
-    <item msgid="6069075827077845520">"4M"</item>
-    <item msgid="8243549501764402572">"16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"ಆಫ್"</item>
     <item msgid="4064786181089783077">"64K"</item>
     <item msgid="3052710745383602630">"256K"</item>
     <item msgid="3691785423374588514">"1M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"ಆಫ್"</item>
-    <item msgid="4195153527464162486">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್‌ಗೆ 64K"</item>
-    <item msgid="7464037639415220106">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್‌ಗೆ 256K"</item>
-    <item msgid="8539423820514360724">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್‌ಗೆ 1M"</item>
-    <item msgid="1984761927103140651">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್‌ಗೆ 4M"</item>
-    <item msgid="7892098981256010498">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್‌ಗೆ 16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"ಆಫ್"</item>
     <item msgid="6014837961827347618">"ಎಲ್ಲಾ"</item>
diff --git a/packages/SettingsLib/res/values-ko/arrays.xml b/packages/SettingsLib/res/values-ko/arrays.xml
index 9a18c16..648188f 100644
--- a/packages/SettingsLib/res/values-ko/arrays.xml
+++ b/packages/SettingsLib/res/values-ko/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", 활성(미디어)"</item>
     <item msgid="5001852592115448348">", 활성(휴대전화)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"사용 안함"</item>
-    <item msgid="7839165897132179888">"64K"</item>
-    <item msgid="2715700596495505626">"256K"</item>
-    <item msgid="7099386891713159947">"1M"</item>
-    <item msgid="6069075827077845520">"4M"</item>
-    <item msgid="8243549501764402572">"16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"사용 안함"</item>
     <item msgid="4064786181089783077">"64K"</item>
     <item msgid="3052710745383602630">"256K"</item>
     <item msgid="3691785423374588514">"1M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"사용 안함"</item>
-    <item msgid="4195153527464162486">"로그 버퍼당 64K"</item>
-    <item msgid="7464037639415220106">"로그 버퍼당 256K"</item>
-    <item msgid="8539423820514360724">"로그 버퍼당 1M"</item>
-    <item msgid="1984761927103140651">"로그 버퍼당 4M"</item>
-    <item msgid="7892098981256010498">"로그 버퍼당 16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"사용 안함"</item>
     <item msgid="6014837961827347618">"전체"</item>
diff --git a/packages/SettingsLib/res/values-ky/arrays.xml b/packages/SettingsLib/res/values-ky/arrays.xml
index f5e812d..295c174 100644
--- a/packages/SettingsLib/res/values-ky/arrays.xml
+++ b/packages/SettingsLib/res/values-ky/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", жандырылган (аудио)"</item>
     <item msgid="5001852592115448348">", жандырылган (телефон)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Өчүк"</item>
-    <item msgid="7839165897132179888">"64K"</item>
-    <item msgid="2715700596495505626">"256K"</item>
-    <item msgid="7099386891713159947">"1M"</item>
-    <item msgid="6069075827077845520">"4M"</item>
-    <item msgid="8243549501764402572">"16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Өчүк"</item>
     <item msgid="4064786181089783077">"64K"</item>
     <item msgid="3052710745383602630">"256K"</item>
     <item msgid="3691785423374588514">"1M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Өчүк"</item>
-    <item msgid="4195153527464162486">"Буфер: 64КБ ашпашы керек"</item>
-    <item msgid="7464037639415220106">"Буфер: 256КБ ашпашы керек"</item>
-    <item msgid="8539423820514360724">"Буфер: 1М ашпашы керек"</item>
-    <item msgid="1984761927103140651">"Буфер: 4М ашпашы керек"</item>
-    <item msgid="7892098981256010498">"Буфер: 16М ашпашы керек"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Өчүк"</item>
     <item msgid="6014837961827347618">"Бардыгы"</item>
diff --git a/packages/SettingsLib/res/values-lo/arrays.xml b/packages/SettingsLib/res/values-lo/arrays.xml
index a0fb2b8..c48eb3b 100644
--- a/packages/SettingsLib/res/values-lo/arrays.xml
+++ b/packages/SettingsLib/res/values-lo/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", ອອນລາຍ (ມີເດຍ)"</item>
     <item msgid="5001852592115448348">", ອອນລາຍ (ໂທລະສັບ)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"ປິດ"</item>
-    <item msgid="7839165897132179888">"64K"</item>
-    <item msgid="2715700596495505626">"256K"</item>
-    <item msgid="7099386891713159947">"1M"</item>
-    <item msgid="6069075827077845520">"4M"</item>
-    <item msgid="8243549501764402572">"16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"ປິດ"</item>
     <item msgid="4064786181089783077">"64K"</item>
     <item msgid="3052710745383602630">"256K"</item>
     <item msgid="3691785423374588514">"1M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"ປິດ"</item>
-    <item msgid="4195153527464162486">"ບັບ​ເຟີ 64K ຕໍ່​ບັນທຶກ"</item>
-    <item msgid="7464037639415220106">"ບັບ​ເຟີ 256K ​ຕໍ່​ບັນທຶກ"</item>
-    <item msgid="8539423820514360724">"ບັບ​ເຟີ 1M ​ຕໍ່​ບັນທຶກ"</item>
-    <item msgid="1984761927103140651">"ບັບ​ເຟີ 4M ​ຕໍ່​ບັນທຶກ"</item>
-    <item msgid="7892098981256010498">"ບັບ​ເຟີ 16M ​ຕໍ່​ບັນທຶກ"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"ປິດ"</item>
     <item msgid="6014837961827347618">"ທັງໝົດ"</item>
diff --git a/packages/SettingsLib/res/values-lt/arrays.xml b/packages/SettingsLib/res/values-lt/arrays.xml
index 90a77bf..48b69c8 100644
--- a/packages/SettingsLib/res/values-lt/arrays.xml
+++ b/packages/SettingsLib/res/values-lt/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", aktyvus (medija)"</item>
     <item msgid="5001852592115448348">", aktyvus (telefonas)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Išjungta"</item>
-    <item msgid="7839165897132179888">"64 KB"</item>
-    <item msgid="2715700596495505626">"256 KB"</item>
-    <item msgid="7099386891713159947">"1 MB"</item>
-    <item msgid="6069075827077845520">"4 MB"</item>
-    <item msgid="8243549501764402572">"16 MB"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Išjungta"</item>
     <item msgid="4064786181089783077">"64 KB"</item>
     <item msgid="3052710745383602630">"256 KB"</item>
     <item msgid="3691785423374588514">"1 MB"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Išjungta"</item>
-    <item msgid="4195153527464162486">"64 KB žurnalo buferis"</item>
-    <item msgid="7464037639415220106">"256 KB žurnalo buferis"</item>
-    <item msgid="8539423820514360724">"1 MB žurnalo buferis"</item>
-    <item msgid="1984761927103140651">"4 MB žurnalo buferis"</item>
-    <item msgid="7892098981256010498">"16 MB žurnalo buferis"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Išjungta"</item>
     <item msgid="6014837961827347618">"Viskas"</item>
diff --git a/packages/SettingsLib/res/values-lv/arrays.xml b/packages/SettingsLib/res/values-lv/arrays.xml
index 5891727..81a3721 100644
--- a/packages/SettingsLib/res/values-lv/arrays.xml
+++ b/packages/SettingsLib/res/values-lv/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", aktīva (multivide)"</item>
     <item msgid="5001852592115448348">", aktīva (tālrunis)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Izslēgts"</item>
-    <item msgid="7839165897132179888">"64 KB"</item>
-    <item msgid="2715700596495505626">"256 KB"</item>
-    <item msgid="7099386891713159947">"1 MB"</item>
-    <item msgid="6069075827077845520">"4 MB"</item>
-    <item msgid="8243549501764402572">"16 MB"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Izslēgts"</item>
     <item msgid="4064786181089783077">"64 KB"</item>
     <item msgid="3052710745383602630">"256 KB"</item>
     <item msgid="3691785423374588514">"1 MB"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Izslēgts"</item>
-    <item msgid="4195153527464162486">"64 KB vienam žurnāla buferim"</item>
-    <item msgid="7464037639415220106">"256 KB vienam žurnāla buferim"</item>
-    <item msgid="8539423820514360724">"1 MB vienam žurnāla buferim"</item>
-    <item msgid="1984761927103140651">"4 MB vienam žurnāla buferim"</item>
-    <item msgid="7892098981256010498">"16 MB vienam žurnāla buferim"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Izslēgts"</item>
     <item msgid="6014837961827347618">"Visi"</item>
diff --git a/packages/SettingsLib/res/values-mk/arrays.xml b/packages/SettingsLib/res/values-mk/arrays.xml
index 388e280..90a97c7 100644
--- a/packages/SettingsLib/res/values-mk/arrays.xml
+++ b/packages/SettingsLib/res/values-mk/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", активен (аудиосодржини)"</item>
     <item msgid="5001852592115448348">", активен (телефон)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Исклучено"</item>
-    <item msgid="7839165897132179888">"64.000"</item>
-    <item msgid="2715700596495505626">"256.000"</item>
-    <item msgid="7099386891713159947">"1 M"</item>
-    <item msgid="6069075827077845520">"4 M"</item>
-    <item msgid="8243549501764402572">"16 M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Исклучено"</item>
     <item msgid="4064786181089783077">"64.000"</item>
     <item msgid="3052710745383602630">"256.000"</item>
     <item msgid="3691785423374588514">"1 M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Исклучено"</item>
-    <item msgid="4195153527464162486">"64 K/меѓумеморија"</item>
-    <item msgid="7464037639415220106">"256 K/меѓумеморија"</item>
-    <item msgid="8539423820514360724">"1 M/меѓумеморија"</item>
-    <item msgid="1984761927103140651">"4 M/меѓумеморија"</item>
-    <item msgid="7892098981256010498">"16 M/меѓумеморија"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Исклучено"</item>
     <item msgid="6014837961827347618">"Сите"</item>
diff --git a/packages/SettingsLib/res/values-ml/arrays.xml b/packages/SettingsLib/res/values-ml/arrays.xml
index cb31d22..5ea0615 100644
--- a/packages/SettingsLib/res/values-ml/arrays.xml
+++ b/packages/SettingsLib/res/values-ml/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", സജീവ (മീഡിയ)"</item>
     <item msgid="5001852592115448348">", സജീവമായ (ഫോൺ)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"ഓഫ്"</item>
-    <item msgid="7839165897132179888">"64K"</item>
-    <item msgid="2715700596495505626">"256K"</item>
-    <item msgid="7099386891713159947">"1M"</item>
-    <item msgid="6069075827077845520">"4M"</item>
-    <item msgid="8243549501764402572">"16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"ഓഫ്"</item>
     <item msgid="4064786181089783077">"64K"</item>
     <item msgid="3052710745383602630">"256K"</item>
     <item msgid="3691785423374588514">"1M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"ഓഫ്"</item>
-    <item msgid="4195153527464162486">"ഓരോ ലോഗ് ബഫറിനും 64K"</item>
-    <item msgid="7464037639415220106">"ഓരോ ലോഗ് ബഫറിനും 256K"</item>
-    <item msgid="8539423820514360724">"ഓരോ ലോഗ് ബഫറിനും 1M"</item>
-    <item msgid="1984761927103140651">"ഓരോ ലോഗ് ബഫറിനും 4M"</item>
-    <item msgid="7892098981256010498">"ഓരോ ലോഗ് ബഫറിനും 16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"ഓഫ്"</item>
     <item msgid="6014837961827347618">"എല്ലാം"</item>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 485a228..1455669 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -576,8 +576,7 @@
     <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
     <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
-    <!-- no translation found for data_connection_carrier_wifi (2250268321065848954) -->
-    <skip />
+    <string name="data_connection_carrier_wifi" msgid="2250268321065848954">"CWF"</string>
     <string name="cell_data_off_content_description" msgid="2280700839891636498">"മൊബൈൽ ഡാറ്റ ഓഫാണ്"</string>
     <string name="not_default_data_content_description" msgid="6517068332106592887">"ഡാറ്റ ഉപയോഗിക്കുന്നതിന് സജ്ജീകരിച്ചിട്ടില്ല"</string>
     <string name="accessibility_no_phone" msgid="2687419663127582503">"ഫോൺ സിഗ്‌നൽ ഒന്നുമില്ല."</string>
diff --git a/packages/SettingsLib/res/values-mn/arrays.xml b/packages/SettingsLib/res/values-mn/arrays.xml
index 6a33b48..e58ff66 100644
--- a/packages/SettingsLib/res/values-mn/arrays.xml
+++ b/packages/SettingsLib/res/values-mn/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", идэвхтэй (медиа)"</item>
     <item msgid="5001852592115448348">", идэвхтэй (утас)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Идэвхгүй"</item>
-    <item msgid="7839165897132179888">"64000"</item>
-    <item msgid="2715700596495505626">"256000"</item>
-    <item msgid="7099386891713159947">"1 сая"</item>
-    <item msgid="6069075827077845520">"4 сая"</item>
-    <item msgid="8243549501764402572">"16 сая"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Идэвхгүй"</item>
     <item msgid="4064786181089783077">"64000"</item>
     <item msgid="3052710745383602630">"256000"</item>
     <item msgid="3691785423374588514">"1 сая"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Идэвхгүй"</item>
-    <item msgid="4195153527464162486">"лог буфер бүрд 64K"</item>
-    <item msgid="7464037639415220106">"лог буфер бүрд 256K"</item>
-    <item msgid="8539423820514360724">"лог буфер бүрд 1M"</item>
-    <item msgid="1984761927103140651">"лог буфер бүрд 4M"</item>
-    <item msgid="7892098981256010498">"лог буфер бүрд 16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Идэвхгүй"</item>
     <item msgid="6014837961827347618">"Бүгд"</item>
diff --git a/packages/SettingsLib/res/values-mr/arrays.xml b/packages/SettingsLib/res/values-mr/arrays.xml
index 8abf290..aaf51b3 100644
--- a/packages/SettingsLib/res/values-mr/arrays.xml
+++ b/packages/SettingsLib/res/values-mr/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", अ‍ॅक्टिव्ह (मीडिया)"</item>
     <item msgid="5001852592115448348">", अ‍ॅक्टिव्ह (फोन)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"बंद"</item>
-    <item msgid="7839165897132179888">"64K"</item>
-    <item msgid="2715700596495505626">"256K"</item>
-    <item msgid="7099386891713159947">"1M"</item>
-    <item msgid="6069075827077845520">"4M"</item>
-    <item msgid="8243549501764402572">"16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"बंद"</item>
     <item msgid="4064786181089783077">"64K"</item>
     <item msgid="3052710745383602630">"256K"</item>
     <item msgid="3691785423374588514">"1M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"बंद"</item>
-    <item msgid="4195153527464162486">"प्रति लॉग बफर 64K"</item>
-    <item msgid="7464037639415220106">"प्रति लॉग बफर 256K"</item>
-    <item msgid="8539423820514360724">"प्रति लॉग बफर 1M"</item>
-    <item msgid="1984761927103140651">"प्रति लॉग बफर 4M"</item>
-    <item msgid="7892098981256010498">"प्रति लॉग बफर 16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"बंद"</item>
     <item msgid="6014837961827347618">"सर्व"</item>
diff --git a/packages/SettingsLib/res/values-ms/arrays.xml b/packages/SettingsLib/res/values-ms/arrays.xml
index 15fad67..d2fc10e 100644
--- a/packages/SettingsLib/res/values-ms/arrays.xml
+++ b/packages/SettingsLib/res/values-ms/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", aktif (media)"</item>
     <item msgid="5001852592115448348">", aktif (telefon)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Mati"</item>
-    <item msgid="7839165897132179888">"64K"</item>
-    <item msgid="2715700596495505626">"256K"</item>
-    <item msgid="7099386891713159947">"1M"</item>
-    <item msgid="6069075827077845520">"4M"</item>
-    <item msgid="8243549501764402572">"16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Mati"</item>
     <item msgid="4064786181089783077">"64K"</item>
     <item msgid="3052710745383602630">"256K"</item>
     <item msgid="3691785423374588514">"1M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Mati"</item>
-    <item msgid="4195153527464162486">"64K per penimbal log"</item>
-    <item msgid="7464037639415220106">"256K per penimbal log"</item>
-    <item msgid="8539423820514360724">"1M per penimbal log"</item>
-    <item msgid="1984761927103140651">"4M per penimbal log"</item>
-    <item msgid="7892098981256010498">"16M per penimbal log"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Mati"</item>
     <item msgid="6014837961827347618">"Semua"</item>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 1ba076d..9527793 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -576,8 +576,7 @@
     <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
     <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
-    <!-- no translation found for data_connection_carrier_wifi (2250268321065848954) -->
-    <skip />
+    <string name="data_connection_carrier_wifi" msgid="2250268321065848954">"CWF"</string>
     <string name="cell_data_off_content_description" msgid="2280700839891636498">"Data mudah alih dimatikan"</string>
     <string name="not_default_data_content_description" msgid="6517068332106592887">"Tidak ditetapkan untuk menggunakan data"</string>
     <string name="accessibility_no_phone" msgid="2687419663127582503">"Tiada telefon."</string>
diff --git a/packages/SettingsLib/res/values-my/arrays.xml b/packages/SettingsLib/res/values-my/arrays.xml
index 90bac81..3c69335 100644
--- a/packages/SettingsLib/res/values-my/arrays.xml
+++ b/packages/SettingsLib/res/values-my/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">"၊ ဖွင့်ထားသည် (မီဒီယာ)"</item>
     <item msgid="5001852592115448348">"၊ ဖွင့်ထားသည် (ဖုန်း)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"ပိတ်ရန်"</item>
-    <item msgid="7839165897132179888">"64K"</item>
-    <item msgid="2715700596495505626">"256K"</item>
-    <item msgid="7099386891713159947">"1M"</item>
-    <item msgid="6069075827077845520">"4M"</item>
-    <item msgid="8243549501764402572">"16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"ပိတ်ရန်"</item>
     <item msgid="4064786181089783077">"64K"</item>
     <item msgid="3052710745383602630">"256K"</item>
     <item msgid="3691785423374588514">"1M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"ပိတ်ရန်"</item>
-    <item msgid="4195153527464162486">"မှတ်တမ်းယာယီကြားခံနယ်တစ်ခုလျှင် 64K"</item>
-    <item msgid="7464037639415220106">"မှတ်တမ်းယာယီကြားခံနယ်တစ်ခုလျှင် 256K"</item>
-    <item msgid="8539423820514360724">"မှတ်တမ်းကြားခံနယ် တစ်ခုလျှင် 1M"</item>
-    <item msgid="1984761927103140651">"မှတ်တမ်းယာယီကြားခံနယ်တစ်ခုလျှင် 4M"</item>
-    <item msgid="7892098981256010498">"မှတ်တမ်းယာယီကြားခံနယ်တစ်ခုလျှင် 16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"ပိတ်ရန်"</item>
     <item msgid="6014837961827347618">"အားလုံး"</item>
diff --git a/packages/SettingsLib/res/values-nb/arrays.xml b/packages/SettingsLib/res/values-nb/arrays.xml
index 275018b..5e6ee65 100644
--- a/packages/SettingsLib/res/values-nb/arrays.xml
+++ b/packages/SettingsLib/res/values-nb/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", aktiv (media)"</item>
     <item msgid="5001852592115448348">", aktiv (telefon)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Av"</item>
-    <item msgid="7839165897132179888">"64K"</item>
-    <item msgid="2715700596495505626">"256K"</item>
-    <item msgid="7099386891713159947">"1M"</item>
-    <item msgid="6069075827077845520">"4M"</item>
-    <item msgid="8243549501764402572">"16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Av"</item>
     <item msgid="4064786181089783077">"64K"</item>
     <item msgid="3052710745383602630">"256K"</item>
     <item msgid="3691785423374588514">"1M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Av"</item>
-    <item msgid="4195153527464162486">"64K per loggbuffer"</item>
-    <item msgid="7464037639415220106">"256K per loggbuffer"</item>
-    <item msgid="8539423820514360724">"1M per loggbuffer"</item>
-    <item msgid="1984761927103140651">"4M per loggbuffer"</item>
-    <item msgid="7892098981256010498">"16M per loggbuffer"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Av"</item>
     <item msgid="6014837961827347618">"Alle"</item>
diff --git a/packages/SettingsLib/res/values-ne/arrays.xml b/packages/SettingsLib/res/values-ne/arrays.xml
index 5ee6353..c8b89c7 100644
--- a/packages/SettingsLib/res/values-ne/arrays.xml
+++ b/packages/SettingsLib/res/values-ne/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", सक्रिय (मिडिया)"</item>
     <item msgid="5001852592115448348">", सक्रिय (फोन)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"निष्क्रिय गर्नुहोस्"</item>
-    <item msgid="7839165897132179888">"६४के"</item>
-    <item msgid="2715700596495505626">"२५६के"</item>
-    <item msgid="7099386891713159947">"१एम"</item>
-    <item msgid="6069075827077845520">"४एम"</item>
-    <item msgid="8243549501764402572">"१६एम"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"निष्क्रिय गर्नुहोस्"</item>
     <item msgid="4064786181089783077">"६४के"</item>
     <item msgid="3052710745383602630">"२५६के"</item>
     <item msgid="3691785423374588514">"१एम"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"निष्क्रिय गर्नुहोस्"</item>
-    <item msgid="4195153527464162486">"६४के प्रति लग बफर"</item>
-    <item msgid="7464037639415220106">"२५६के प्रति लग बफर"</item>
-    <item msgid="8539423820514360724">"१एम प्रति लग बफर"</item>
-    <item msgid="1984761927103140651">"४एम प्रति लग बफर"</item>
-    <item msgid="7892098981256010498">"१६एम प्रति लग बफर"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"निष्क्रिय"</item>
     <item msgid="6014837961827347618">"सबै"</item>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index c0e9fe5..5795cc9 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -576,8 +576,7 @@
     <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
     <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
-    <!-- no translation found for data_connection_carrier_wifi (2250268321065848954) -->
-    <skip />
+    <string name="data_connection_carrier_wifi" msgid="2250268321065848954">"CWF"</string>
     <string name="cell_data_off_content_description" msgid="2280700839891636498">"मोबाइल डेटा निष्क्रिय छ"</string>
     <string name="not_default_data_content_description" msgid="6517068332106592887">"डेटा प्रयोग गर्ने गरी सेट गरिएन"</string>
     <string name="accessibility_no_phone" msgid="2687419663127582503">"फोन छैन्।"</string>
diff --git a/packages/SettingsLib/res/values-nl/arrays.xml b/packages/SettingsLib/res/values-nl/arrays.xml
index bfbbae0..a20db9d 100644
--- a/packages/SettingsLib/res/values-nl/arrays.xml
+++ b/packages/SettingsLib/res/values-nl/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", actief (media)"</item>
     <item msgid="5001852592115448348">", actief (telefoon)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Uit"</item>
-    <item msgid="7839165897132179888">"64 K"</item>
-    <item msgid="2715700596495505626">"256 K"</item>
-    <item msgid="7099386891713159947">"1 M"</item>
-    <item msgid="6069075827077845520">"4 M"</item>
-    <item msgid="8243549501764402572">"16 M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Uit"</item>
     <item msgid="4064786181089783077">"64 K"</item>
     <item msgid="3052710745383602630">"256 K"</item>
     <item msgid="3691785423374588514">"1 M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Uit"</item>
-    <item msgid="4195153527464162486">"64 K per logbuffer"</item>
-    <item msgid="7464037639415220106">"256 K per logbuffer"</item>
-    <item msgid="8539423820514360724">"1 M per logbuffer"</item>
-    <item msgid="1984761927103140651">"4 M per logbuffer"</item>
-    <item msgid="7892098981256010498">"16 M per logbuffer"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Uit"</item>
     <item msgid="6014837961827347618">"Alle"</item>
diff --git a/packages/SettingsLib/res/values-or/arrays.xml b/packages/SettingsLib/res/values-or/arrays.xml
index 4a3d5d7..b7de25e 100644
--- a/packages/SettingsLib/res/values-or/arrays.xml
+++ b/packages/SettingsLib/res/values-or/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", ସକ୍ରିୟ (ମିଡିଆ)"</item>
     <item msgid="5001852592115448348">", ସକ୍ରିୟ (ଫୋନ୍)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"ବନ୍ଦ"</item>
-    <item msgid="7839165897132179888">"64K"</item>
-    <item msgid="2715700596495505626">"256K"</item>
-    <item msgid="7099386891713159947">"1M"</item>
-    <item msgid="6069075827077845520">"4M"</item>
-    <item msgid="8243549501764402572">"16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"ବନ୍ଦ"</item>
     <item msgid="4064786181089783077">"64K"</item>
     <item msgid="3052710745383602630">"256K"</item>
     <item msgid="3691785423374588514">"1M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"ବନ୍ଦ"</item>
-    <item msgid="4195153527464162486">"64K ପିଛା ଲଗ୍‌ ବଫର୍‌"</item>
-    <item msgid="7464037639415220106">"256K ଲଗ୍‌ ପ୍ରତି ବଫର୍‌"</item>
-    <item msgid="8539423820514360724">"1M ପ୍ରତି ଲଗ୍‌ ବଫର୍‌"</item>
-    <item msgid="1984761927103140651">"ଲଗ୍‌ ବଫର୍‌ ପ୍ରତି 4M"</item>
-    <item msgid="7892098981256010498">"16M ଲଗ ପିଛା ବଫର୍‌"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"ବନ୍ଦ"</item>
     <item msgid="6014837961827347618">"ସମସ୍ତ"</item>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index ac1ccb6..41e84f9 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -576,8 +576,7 @@
     <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
     <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
-    <!-- no translation found for data_connection_carrier_wifi (2250268321065848954) -->
-    <skip />
+    <string name="data_connection_carrier_wifi" msgid="2250268321065848954">"CWF"</string>
     <string name="cell_data_off_content_description" msgid="2280700839891636498">"ମୋବାଇଲ୍‌ ଡାଟା ବନ୍ଦ ଅଛି"</string>
     <string name="not_default_data_content_description" msgid="6517068332106592887">"ବ୍ୟବହୃତ ଡାଟା ପାଇଁ ସେଟ୍ ହୋଇନାହିଁ"</string>
     <string name="accessibility_no_phone" msgid="2687419663127582503">"କୌଣସି ଫୋନ୍ ନାହିଁ।"</string>
diff --git a/packages/SettingsLib/res/values-pa/arrays.xml b/packages/SettingsLib/res/values-pa/arrays.xml
index d594f3b..c64ee76 100644
--- a/packages/SettingsLib/res/values-pa/arrays.xml
+++ b/packages/SettingsLib/res/values-pa/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", ਕਿਰਿਆਸ਼ੀਲ (ਮੀਡੀਆ)"</item>
     <item msgid="5001852592115448348">", ਕਿਰਿਆਸ਼ੀਲ (ਫ਼ੋਨ)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"ਬੰਦ"</item>
-    <item msgid="7839165897132179888">"64K"</item>
-    <item msgid="2715700596495505626">"256K"</item>
-    <item msgid="7099386891713159947">"1M"</item>
-    <item msgid="6069075827077845520">"4M"</item>
-    <item msgid="8243549501764402572">"16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"ਬੰਦ"</item>
     <item msgid="4064786181089783077">"64K"</item>
     <item msgid="3052710745383602630">"256K"</item>
     <item msgid="3691785423374588514">"1M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"ਬੰਦ"</item>
-    <item msgid="4195153527464162486">"64K ਪ੍ਰਤੀ ਲੌਗ ਬਫ਼ਰ"</item>
-    <item msgid="7464037639415220106">"256K ਪ੍ਰਤੀ ਲੌਗ ਬਫ਼ਰ"</item>
-    <item msgid="8539423820514360724">"1M ਪ੍ਰਤੀ ਲੌਗ ਬਫ਼ਰ"</item>
-    <item msgid="1984761927103140651">"4M ਪ੍ਰਤੀ ਲੌਗ ਬਫ਼ਰ"</item>
-    <item msgid="7892098981256010498">"16M ਪ੍ਰਤੀ ਲੌਗ ਬਫ਼ਰ"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"ਬੰਦ"</item>
     <item msgid="6014837961827347618">"ਸਭ"</item>
diff --git a/packages/SettingsLib/res/values-pl/arrays.xml b/packages/SettingsLib/res/values-pl/arrays.xml
index eb33323..e873b7e 100644
--- a/packages/SettingsLib/res/values-pl/arrays.xml
+++ b/packages/SettingsLib/res/values-pl/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", aktywne (multimedia)"</item>
     <item msgid="5001852592115448348">", aktywne (telefon)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Wył."</item>
-    <item msgid="7839165897132179888">"64 KB"</item>
-    <item msgid="2715700596495505626">"256 KB"</item>
-    <item msgid="7099386891713159947">"1 MB"</item>
-    <item msgid="6069075827077845520">"4 MB"</item>
-    <item msgid="8243549501764402572">"16 MB"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Wył."</item>
     <item msgid="4064786181089783077">"64 KB"</item>
     <item msgid="3052710745383602630">"256 KB"</item>
     <item msgid="3691785423374588514">"1 MB"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Wył."</item>
-    <item msgid="4195153527464162486">"64 KB/bufor dziennika"</item>
-    <item msgid="7464037639415220106">"256 KB/bufor dziennika"</item>
-    <item msgid="8539423820514360724">"1 MB/bufor dziennika"</item>
-    <item msgid="1984761927103140651">"4 MB/bufor dziennika"</item>
-    <item msgid="7892098981256010498">"16 MB/bufor dziennika"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Wyłączone"</item>
     <item msgid="6014837961827347618">"Wszystkie"</item>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index cd6f25c..a57e541 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -578,8 +578,7 @@
     <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
     <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
-    <!-- no translation found for data_connection_carrier_wifi (2250268321065848954) -->
-    <skip />
+    <string name="data_connection_carrier_wifi" msgid="2250268321065848954">"CWF"</string>
     <string name="cell_data_off_content_description" msgid="2280700839891636498">"Wyłączona"</string>
     <string name="not_default_data_content_description" msgid="6517068332106592887">"Nie skonfigurowano do transmisji danych"</string>
     <string name="accessibility_no_phone" msgid="2687419663127582503">"Brak sygnału telefonu."</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/arrays.xml b/packages/SettingsLib/res/values-pt-rBR/arrays.xml
index 81285aa..c0dcec0 100644
--- a/packages/SettingsLib/res/values-pt-rBR/arrays.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", ativo (mídia)"</item>
     <item msgid="5001852592115448348">", ativo (telefone)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Desativado"</item>
-    <item msgid="7839165897132179888">"64 K"</item>
-    <item msgid="2715700596495505626">"256 K"</item>
-    <item msgid="7099386891713159947">"1 M"</item>
-    <item msgid="6069075827077845520">"4 M"</item>
-    <item msgid="8243549501764402572">"16 M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Desativado"</item>
     <item msgid="4064786181089783077">"64 K"</item>
     <item msgid="3052710745383602630">"256 K"</item>
     <item msgid="3691785423374588514">"1 M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Desativado"</item>
-    <item msgid="4195153527464162486">"64 K/buffer de registro"</item>
-    <item msgid="7464037639415220106">"256 K/buffer de registro"</item>
-    <item msgid="8539423820514360724">"1 M/buffer de registro"</item>
-    <item msgid="1984761927103140651">"4 M/buffer de registro"</item>
-    <item msgid="7892098981256010498">"16 M/buffer de registro"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Desativado"</item>
     <item msgid="6014837961827347618">"Todos"</item>
diff --git a/packages/SettingsLib/res/values-pt-rPT/arrays.xml b/packages/SettingsLib/res/values-pt-rPT/arrays.xml
index 019a5f6..de63257 100644
--- a/packages/SettingsLib/res/values-pt-rPT/arrays.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", ativo (multimédia)"</item>
     <item msgid="5001852592115448348">", ativo (telemóvel)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Desativado"</item>
-    <item msgid="7839165897132179888">"64 K"</item>
-    <item msgid="2715700596495505626">"256 K"</item>
-    <item msgid="7099386891713159947">"1 M"</item>
-    <item msgid="6069075827077845520">"4 M"</item>
-    <item msgid="8243549501764402572">"16 M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Desativado"</item>
     <item msgid="4064786181089783077">"64 K"</item>
     <item msgid="3052710745383602630">"256 K"</item>
     <item msgid="3691785423374588514">"1 M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Desativado"</item>
-    <item msgid="4195153527464162486">"64 K por buffer de registo"</item>
-    <item msgid="7464037639415220106">"256 K por buffer de registo"</item>
-    <item msgid="8539423820514360724">"1 M por buffer de registo"</item>
-    <item msgid="1984761927103140651">"4 M por buffer de registo"</item>
-    <item msgid="7892098981256010498">"16 M por buffer de registo"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Desativado"</item>
     <item msgid="6014837961827347618">"Todos"</item>
diff --git a/packages/SettingsLib/res/values-pt/arrays.xml b/packages/SettingsLib/res/values-pt/arrays.xml
index 81285aa..c0dcec0 100644
--- a/packages/SettingsLib/res/values-pt/arrays.xml
+++ b/packages/SettingsLib/res/values-pt/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", ativo (mídia)"</item>
     <item msgid="5001852592115448348">", ativo (telefone)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Desativado"</item>
-    <item msgid="7839165897132179888">"64 K"</item>
-    <item msgid="2715700596495505626">"256 K"</item>
-    <item msgid="7099386891713159947">"1 M"</item>
-    <item msgid="6069075827077845520">"4 M"</item>
-    <item msgid="8243549501764402572">"16 M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Desativado"</item>
     <item msgid="4064786181089783077">"64 K"</item>
     <item msgid="3052710745383602630">"256 K"</item>
     <item msgid="3691785423374588514">"1 M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Desativado"</item>
-    <item msgid="4195153527464162486">"64 K/buffer de registro"</item>
-    <item msgid="7464037639415220106">"256 K/buffer de registro"</item>
-    <item msgid="8539423820514360724">"1 M/buffer de registro"</item>
-    <item msgid="1984761927103140651">"4 M/buffer de registro"</item>
-    <item msgid="7892098981256010498">"16 M/buffer de registro"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Desativado"</item>
     <item msgid="6014837961827347618">"Todos"</item>
diff --git a/packages/SettingsLib/res/values-ro/arrays.xml b/packages/SettingsLib/res/values-ro/arrays.xml
index 48a3fa7..0fe0ef0 100644
--- a/packages/SettingsLib/res/values-ro/arrays.xml
+++ b/packages/SettingsLib/res/values-ro/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", activ (media)"</item>
     <item msgid="5001852592115448348">", activ (telefon)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Dezactivată"</item>
-    <item msgid="7839165897132179888">"64 KB"</item>
-    <item msgid="2715700596495505626">"256 KB"</item>
-    <item msgid="7099386891713159947">"1 MB"</item>
-    <item msgid="6069075827077845520">"4 MB"</item>
-    <item msgid="8243549501764402572">"16 MB"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Dezactivată"</item>
     <item msgid="4064786181089783077">"64 KB"</item>
     <item msgid="3052710745383602630">"256 KB"</item>
     <item msgid="3691785423374588514">"1 MB"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Dezactivată"</item>
-    <item msgid="4195153527464162486">"64 KB/mem. temporară de înregistrări în jurnal"</item>
-    <item msgid="7464037639415220106">"256 KB/mem. temporară de înregistrări în jurnal"</item>
-    <item msgid="8539423820514360724">"1 MB/mem. temporară de înregistrări în jurnal"</item>
-    <item msgid="1984761927103140651">"4 MB/mem. temporară de înregistrări în jurnal"</item>
-    <item msgid="7892098981256010498">"16 MB/mem. temporară de înregistrări în jurnal"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Dezactivată"</item>
     <item msgid="6014837961827347618">"Toate"</item>
diff --git a/packages/SettingsLib/res/values-ru/arrays.xml b/packages/SettingsLib/res/values-ru/arrays.xml
index 5617aa6..84c3dc6 100644
--- a/packages/SettingsLib/res/values-ru/arrays.xml
+++ b/packages/SettingsLib/res/values-ru/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", активно (A2DP)"</item>
     <item msgid="5001852592115448348">", активно (HSP/HFP)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Отключено"</item>
-    <item msgid="7839165897132179888">"64 КБ"</item>
-    <item msgid="2715700596495505626">"256 КБ"</item>
-    <item msgid="7099386891713159947">"1 МБ"</item>
-    <item msgid="6069075827077845520">"4 МБ"</item>
-    <item msgid="8243549501764402572">"16 МБ"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Отключено"</item>
     <item msgid="4064786181089783077">"64 КБ"</item>
     <item msgid="3052710745383602630">"256 КБ"</item>
     <item msgid="3691785423374588514">"1 МБ"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Отключено"</item>
-    <item msgid="4195153527464162486">"Буфер: макс. 64 КБ"</item>
-    <item msgid="7464037639415220106">"Буфер: макс. 256 КБ"</item>
-    <item msgid="8539423820514360724">"Буфер: макс. 1 МБ"</item>
-    <item msgid="1984761927103140651">"Буфер: макс. 4 МБ"</item>
-    <item msgid="7892098981256010498">"Буфер: макс. 16 МБ"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Отключено"</item>
     <item msgid="6014837961827347618">"Все"</item>
diff --git a/packages/SettingsLib/res/values-si/arrays.xml b/packages/SettingsLib/res/values-si/arrays.xml
index 01d0dd2..81d0bbb 100644
--- a/packages/SettingsLib/res/values-si/arrays.xml
+++ b/packages/SettingsLib/res/values-si/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", ක්‍රියාකාරී (මාධ්‍ය)"</item>
     <item msgid="5001852592115448348">", ක්‍රියාකාරී (දුරකථන)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"ක්‍රියාවිරහිතය"</item>
-    <item msgid="7839165897132179888">"64K"</item>
-    <item msgid="2715700596495505626">"256K"</item>
-    <item msgid="7099386891713159947">"1M"</item>
-    <item msgid="6069075827077845520">"4M"</item>
-    <item msgid="8243549501764402572">"16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"ක්‍රියාවිරහිතය"</item>
     <item msgid="4064786181089783077">"64K"</item>
     <item msgid="3052710745383602630">"256K"</item>
     <item msgid="3691785423374588514">"1M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"ක්‍රියාවිරහිතය"</item>
-    <item msgid="4195153527464162486">"ලොග අන්තරාවකට 64K"</item>
-    <item msgid="7464037639415220106">"ලොග අන්තරාවකට 256K"</item>
-    <item msgid="8539423820514360724">"ලොග අන්තරාවකට 1M"</item>
-    <item msgid="1984761927103140651">"ලොග අන්තරාවකට 4M"</item>
-    <item msgid="7892098981256010498">"ලොග අන්තරාවකට 16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"ක්‍රියාවිරහිතය"</item>
     <item msgid="6014837961827347618">"සියලු"</item>
diff --git a/packages/SettingsLib/res/values-sk/arrays.xml b/packages/SettingsLib/res/values-sk/arrays.xml
index 5dcf791..2826cb3 100644
--- a/packages/SettingsLib/res/values-sk/arrays.xml
+++ b/packages/SettingsLib/res/values-sk/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", aktívne (médiá)"</item>
     <item msgid="5001852592115448348">", aktívne (telefón)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Vypnuté"</item>
-    <item msgid="7839165897132179888">"64 kB"</item>
-    <item msgid="2715700596495505626">"256 kB"</item>
-    <item msgid="7099386891713159947">"1 MB"</item>
-    <item msgid="6069075827077845520">"4 MB"</item>
-    <item msgid="8243549501764402572">"16 MB"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Vypnuté"</item>
     <item msgid="4064786181089783077">"64 kB"</item>
     <item msgid="3052710745383602630">"256 kB"</item>
     <item msgid="3691785423374588514">"1 MB"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Vypnuté"</item>
-    <item msgid="4195153527464162486">"64 kB na vyrov. pamäť denníka"</item>
-    <item msgid="7464037639415220106">"256 kB na vyrov. pamäť denníka"</item>
-    <item msgid="8539423820514360724">"1 MB na vyrov. pam. denníka"</item>
-    <item msgid="1984761927103140651">"4 MB na vyrov. pamäť denníka"</item>
-    <item msgid="7892098981256010498">"16 MB na vyrov. pamäť denníka"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Vypnuté"</item>
     <item msgid="6014837961827347618">"Všetko"</item>
diff --git a/packages/SettingsLib/res/values-sl/arrays.xml b/packages/SettingsLib/res/values-sl/arrays.xml
index 7ba23af..26c6e6e 100644
--- a/packages/SettingsLib/res/values-sl/arrays.xml
+++ b/packages/SettingsLib/res/values-sl/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", aktivno (predstavnost)"</item>
     <item msgid="5001852592115448348">", aktivno (telefon)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Izklopljeno"</item>
-    <item msgid="7839165897132179888">"64 K"</item>
-    <item msgid="2715700596495505626">"256 K"</item>
-    <item msgid="7099386891713159947">"1 M"</item>
-    <item msgid="6069075827077845520">"4 M"</item>
-    <item msgid="8243549501764402572">"16 M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Izklopljeno"</item>
     <item msgid="4064786181089783077">"64 K"</item>
     <item msgid="3052710745383602630">"256 K"</item>
     <item msgid="3691785423374588514">"1 M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Izklopljeno"</item>
-    <item msgid="4195153527464162486">"64 K/medpomnilnik dnevnika"</item>
-    <item msgid="7464037639415220106">"256 K/medpomnilnik dnevnika"</item>
-    <item msgid="8539423820514360724">"1 M/medpomnilnik dnevnika"</item>
-    <item msgid="1984761927103140651">"4 M/medpomnilnik dnevnika"</item>
-    <item msgid="7892098981256010498">"16 M/medpomnilnik dnevnika"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Izklopljeno"</item>
     <item msgid="6014837961827347618">"Vse"</item>
diff --git a/packages/SettingsLib/res/values-sq/arrays.xml b/packages/SettingsLib/res/values-sq/arrays.xml
index fccfc2f..3db2e6b 100644
--- a/packages/SettingsLib/res/values-sq/arrays.xml
+++ b/packages/SettingsLib/res/values-sq/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", aktiv (media)"</item>
     <item msgid="5001852592115448348">", aktiv (telefoni)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Joaktiv"</item>
-    <item msgid="7839165897132179888">"64 mijë"</item>
-    <item msgid="2715700596495505626">"256 mijë"</item>
-    <item msgid="7099386891713159947">"1 milion"</item>
-    <item msgid="6069075827077845520">"4 milionë"</item>
-    <item msgid="8243549501764402572">"16 milionë"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Joaktiv"</item>
     <item msgid="4064786181089783077">"64 mijë"</item>
     <item msgid="3052710745383602630">"256 mijë"</item>
     <item msgid="3691785423374588514">"1 milion"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Joaktiv"</item>
-    <item msgid="4195153527464162486">"64 mijë/memorie regjistrimi"</item>
-    <item msgid="7464037639415220106">"256 mijë/memorie regjistrimi"</item>
-    <item msgid="8539423820514360724">"1 milion/memorie regjistrimi"</item>
-    <item msgid="1984761927103140651">"4 milionë/memorie regjistrimi"</item>
-    <item msgid="7892098981256010498">"16 milionë/memorie regjistrimi"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Joaktive"</item>
     <item msgid="6014837961827347618">"Të gjitha"</item>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index b4e5db9..d5c0231 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -576,8 +576,7 @@
     <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
     <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
-    <!-- no translation found for data_connection_carrier_wifi (2250268321065848954) -->
-    <skip />
+    <string name="data_connection_carrier_wifi" msgid="2250268321065848954">"CWF"</string>
     <string name="cell_data_off_content_description" msgid="2280700839891636498">"Të dhënat celulare janë joaktive"</string>
     <string name="not_default_data_content_description" msgid="6517068332106592887">"Nuk është caktuar të përdorë të dhënat"</string>
     <string name="accessibility_no_phone" msgid="2687419663127582503">"Nuk ka telefon."</string>
diff --git a/packages/SettingsLib/res/values-sr/arrays.xml b/packages/SettingsLib/res/values-sr/arrays.xml
index 11b4b76..ec4da5a 100644
--- a/packages/SettingsLib/res/values-sr/arrays.xml
+++ b/packages/SettingsLib/res/values-sr/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", активан (медијски)"</item>
     <item msgid="5001852592115448348">", активан (телефон)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Искључено"</item>
-    <item msgid="7839165897132179888">"64 kB"</item>
-    <item msgid="2715700596495505626">"256 kB"</item>
-    <item msgid="7099386891713159947">"1 MB"</item>
-    <item msgid="6069075827077845520">"4 MB"</item>
-    <item msgid="8243549501764402572">"16 MB"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Искључено"</item>
     <item msgid="4064786181089783077">"64 kB"</item>
     <item msgid="3052710745383602630">"256 kB"</item>
     <item msgid="3691785423374588514">"1 MB"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Искључено"</item>
-    <item msgid="4195153527464162486">"64 kB по међумеморији евиденције"</item>
-    <item msgid="7464037639415220106">"256 kB по међумеморији евиденције"</item>
-    <item msgid="8539423820514360724">"1 MB по међумеморији евиденције"</item>
-    <item msgid="1984761927103140651">"4 MB по међумеморији евиденције"</item>
-    <item msgid="7892098981256010498">"16 MB по међумеморији евиденције"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Искључено"</item>
     <item msgid="6014837961827347618">"Све"</item>
diff --git a/packages/SettingsLib/res/values-sv/arrays.xml b/packages/SettingsLib/res/values-sv/arrays.xml
index be68c71..b631f44 100644
--- a/packages/SettingsLib/res/values-sv/arrays.xml
+++ b/packages/SettingsLib/res/values-sv/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", aktiv (media)"</item>
     <item msgid="5001852592115448348">", aktiv (telefon)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Av"</item>
-    <item msgid="7839165897132179888">"64 kB"</item>
-    <item msgid="2715700596495505626">"256 kB"</item>
-    <item msgid="7099386891713159947">"1 MB"</item>
-    <item msgid="6069075827077845520">"4 MB"</item>
-    <item msgid="8243549501764402572">"16 MB"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Av"</item>
     <item msgid="4064786181089783077">"64 kB"</item>
     <item msgid="3052710745383602630">"256 kB"</item>
     <item msgid="3691785423374588514">"1 MB"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Av"</item>
-    <item msgid="4195153527464162486">"64 kB/loggbuffert"</item>
-    <item msgid="7464037639415220106">"256 kB/loggbuffert"</item>
-    <item msgid="8539423820514360724">"1 MB/loggbuffert"</item>
-    <item msgid="1984761927103140651">"4 MB/loggbuffert"</item>
-    <item msgid="7892098981256010498">"16 MB/loggbuffert"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Av"</item>
     <item msgid="6014837961827347618">"Alla"</item>
diff --git a/packages/SettingsLib/res/values-sw/arrays.xml b/packages/SettingsLib/res/values-sw/arrays.xml
index da99b91..cd15e2c 100644
--- a/packages/SettingsLib/res/values-sw/arrays.xml
+++ b/packages/SettingsLib/res/values-sw/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", inatumika (maudhui)"</item>
     <item msgid="5001852592115448348">", inatumika (simu)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Imezimwa"</item>
-    <item msgid="7839165897132179888">"K64"</item>
-    <item msgid="2715700596495505626">"K256"</item>
-    <item msgid="7099386891713159947">"M1"</item>
-    <item msgid="6069075827077845520">"M4"</item>
-    <item msgid="8243549501764402572">"M16"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Imezimwa"</item>
     <item msgid="4064786181089783077">"K64"</item>
     <item msgid="3052710745383602630">"K256"</item>
     <item msgid="3691785423374588514">"M1"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Imezimwa"</item>
-    <item msgid="4195153527464162486">"K64 kwa kila akiba ya kumbukumbu"</item>
-    <item msgid="7464037639415220106">"K256 kwa kila akiba ya kumbukumbu"</item>
-    <item msgid="8539423820514360724">"M1 kwa kila akiba ya kumbukumbu"</item>
-    <item msgid="1984761927103140651">"M4 kwa kila akiba ya kumbukumbu"</item>
-    <item msgid="7892098981256010498">"M16 kwa kila akiba ya kumbukumbu"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Yamezimwa"</item>
     <item msgid="6014837961827347618">"Zote"</item>
diff --git a/packages/SettingsLib/res/values-ta/arrays.xml b/packages/SettingsLib/res/values-ta/arrays.xml
index 1c55954..01b0a8e 100644
--- a/packages/SettingsLib/res/values-ta/arrays.xml
+++ b/packages/SettingsLib/res/values-ta/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", செயலில் உள்ளது (மீடியா)"</item>
     <item msgid="5001852592115448348">", செயலில் உள்ளது (மொபைல்)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"ஆஃப்"</item>
-    <item msgid="7839165897132179888">"64K"</item>
-    <item msgid="2715700596495505626">"256K"</item>
-    <item msgid="7099386891713159947">"1M"</item>
-    <item msgid="6069075827077845520">"4M"</item>
-    <item msgid="8243549501764402572">"16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"ஆஃப்"</item>
     <item msgid="4064786181089783077">"64K"</item>
     <item msgid="3052710745383602630">"256K"</item>
     <item msgid="3691785423374588514">"1M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"ஆஃப்"</item>
-    <item msgid="4195153527464162486">"64K / லாக் பஃபர்"</item>
-    <item msgid="7464037639415220106">"256K / லாக் பஃபர்"</item>
-    <item msgid="8539423820514360724">"1M / லாக் பஃபர்"</item>
-    <item msgid="1984761927103140651">"4M / லாக் பஃபர்"</item>
-    <item msgid="7892098981256010498">"16M / லாக் பஃபர்"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"ஆஃப்"</item>
     <item msgid="6014837961827347618">"எல்லாம்"</item>
diff --git a/packages/SettingsLib/res/values-te/arrays.xml b/packages/SettingsLib/res/values-te/arrays.xml
index e1c0406..4bdd55b 100644
--- a/packages/SettingsLib/res/values-te/arrays.xml
+++ b/packages/SettingsLib/res/values-te/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", (మీడియా) సక్రియంగా ఉంది"</item>
     <item msgid="5001852592115448348">", (ఫోన్) సక్రియంగా ఉంది"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"ఆఫ్"</item>
-    <item msgid="7839165897132179888">"64K"</item>
-    <item msgid="2715700596495505626">"256K"</item>
-    <item msgid="7099386891713159947">"1M"</item>
-    <item msgid="6069075827077845520">"4M"</item>
-    <item msgid="8243549501764402572">"16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"ఆఫ్"</item>
     <item msgid="4064786181089783077">"64K"</item>
     <item msgid="3052710745383602630">"256K"</item>
     <item msgid="3691785423374588514">"1M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"ఆఫ్ చేయబడింది"</item>
-    <item msgid="4195153527464162486">"లాగ్ బఫర్‌కి 64K"</item>
-    <item msgid="7464037639415220106">"లాగ్ బఫర్‌కి 256K"</item>
-    <item msgid="8539423820514360724">"లాగ్ బఫర్‌కి 1M"</item>
-    <item msgid="1984761927103140651">"లాగ్ బఫర్‌కి 4M"</item>
-    <item msgid="7892098981256010498">"లాగ్ బఫర్‌కి 16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"ఆఫ్ చేయి"</item>
     <item msgid="6014837961827347618">"అన్నీ"</item>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 33f082d..897abea 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -576,8 +576,7 @@
     <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
     <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
-    <!-- no translation found for data_connection_carrier_wifi (2250268321065848954) -->
-    <skip />
+    <string name="data_connection_carrier_wifi" msgid="2250268321065848954">"CWF"</string>
     <string name="cell_data_off_content_description" msgid="2280700839891636498">"మొబైల్ డేటా ఆఫ్‌లో ఉంది"</string>
     <string name="not_default_data_content_description" msgid="6517068332106592887">"డేటాను ఉపయోగించే విధంగా సెట్ చేయలేదు"</string>
     <string name="accessibility_no_phone" msgid="2687419663127582503">"ఫోన్ లేదు."</string>
diff --git a/packages/SettingsLib/res/values-th/arrays.xml b/packages/SettingsLib/res/values-th/arrays.xml
index 21fe6e4..9f6080b 100644
--- a/packages/SettingsLib/res/values-th/arrays.xml
+++ b/packages/SettingsLib/res/values-th/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">"ใช้งานอยู่ (สื่อ)"</item>
     <item msgid="5001852592115448348">"ใช้งานอยู่ (โทรศัพท์)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"ปิด"</item>
-    <item msgid="7839165897132179888">"64 K"</item>
-    <item msgid="2715700596495505626">"256 K"</item>
-    <item msgid="7099386891713159947">"1 M"</item>
-    <item msgid="6069075827077845520">"4 M"</item>
-    <item msgid="8243549501764402572">"16 M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"ปิด"</item>
     <item msgid="4064786181089783077">"64 K"</item>
     <item msgid="3052710745383602630">"256 K"</item>
     <item msgid="3691785423374588514">"1 M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"ปิด"</item>
-    <item msgid="4195153527464162486">"64 K ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
-    <item msgid="7464037639415220106">"256 K ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
-    <item msgid="8539423820514360724">"1 M ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
-    <item msgid="1984761927103140651">"4 M ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
-    <item msgid="7892098981256010498">"16 M ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"ปิด"</item>
     <item msgid="6014837961827347618">"ทั้งหมด"</item>
diff --git a/packages/SettingsLib/res/values-tl/arrays.xml b/packages/SettingsLib/res/values-tl/arrays.xml
index 9f07cff..ab68a68 100644
--- a/packages/SettingsLib/res/values-tl/arrays.xml
+++ b/packages/SettingsLib/res/values-tl/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", aktibo (media)"</item>
     <item msgid="5001852592115448348">", aktibo (telepono)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"I-off"</item>
-    <item msgid="7839165897132179888">"64K"</item>
-    <item msgid="2715700596495505626">"256K"</item>
-    <item msgid="7099386891713159947">"1M"</item>
-    <item msgid="6069075827077845520">"4M"</item>
-    <item msgid="8243549501764402572">"16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"I-off"</item>
     <item msgid="4064786181089783077">"64K"</item>
     <item msgid="3052710745383602630">"256K"</item>
     <item msgid="3691785423374588514">"1M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"I-off"</item>
-    <item msgid="4195153527464162486">"64K kada log buffer"</item>
-    <item msgid="7464037639415220106">"256K kada log buffer"</item>
-    <item msgid="8539423820514360724">"1M kada log buffer"</item>
-    <item msgid="1984761927103140651">"4M kada log buffer"</item>
-    <item msgid="7892098981256010498">"16M kada log buffer"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Naka-off"</item>
     <item msgid="6014837961827347618">"Lahat"</item>
diff --git a/packages/SettingsLib/res/values-tr/arrays.xml b/packages/SettingsLib/res/values-tr/arrays.xml
index fc90c9a..d5d578c 100644
--- a/packages/SettingsLib/res/values-tr/arrays.xml
+++ b/packages/SettingsLib/res/values-tr/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", etkin (medya)"</item>
     <item msgid="5001852592115448348">", etkin (telefon)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Kapalı"</item>
-    <item msgid="7839165897132179888">"64 KB"</item>
-    <item msgid="2715700596495505626">"256 KB"</item>
-    <item msgid="7099386891713159947">"1 MB"</item>
-    <item msgid="6069075827077845520">"4 MB"</item>
-    <item msgid="8243549501764402572">"16 MB"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Kapalı"</item>
     <item msgid="4064786181089783077">"64 KB"</item>
     <item msgid="3052710745383602630">"256 KB"</item>
     <item msgid="3691785423374588514">"1 MB"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Kapalı"</item>
-    <item msgid="4195153527464162486">"Günlük arabelleği başına 64 KB"</item>
-    <item msgid="7464037639415220106">"Günlük arabelleği başına 256 KB"</item>
-    <item msgid="8539423820514360724">"Günlük arabelleği başına 1 MB"</item>
-    <item msgid="1984761927103140651">"Günlük arabelleği başına 4 MB"</item>
-    <item msgid="7892098981256010498">"Günlük arabelleği başına 16 MB"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Kapalı"</item>
     <item msgid="6014837961827347618">"Tümü"</item>
diff --git a/packages/SettingsLib/res/values-uk/arrays.xml b/packages/SettingsLib/res/values-uk/arrays.xml
index 4405c37..41922a3 100644
--- a/packages/SettingsLib/res/values-uk/arrays.xml
+++ b/packages/SettingsLib/res/values-uk/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", активний (лише для медіа)"</item>
     <item msgid="5001852592115448348">", активний (лише для телефона)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Вимкнено"</item>
-    <item msgid="7839165897132179888">"64 КБ"</item>
-    <item msgid="2715700596495505626">"256 КБ"</item>
-    <item msgid="7099386891713159947">"1 МБ"</item>
-    <item msgid="6069075827077845520">"4 МБ"</item>
-    <item msgid="8243549501764402572">"16 МБ"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Вимкнено"</item>
     <item msgid="4064786181089783077">"64 КБ"</item>
     <item msgid="3052710745383602630">"256 КБ"</item>
     <item msgid="3691785423374588514">"1 МБ"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Вимкнено"</item>
-    <item msgid="4195153527464162486">"Буфер журналу: 64 КБ"</item>
-    <item msgid="7464037639415220106">"Буфер журналу: 256 КБ"</item>
-    <item msgid="8539423820514360724">"Буфер журналу: 1 МБ"</item>
-    <item msgid="1984761927103140651">"Буфер журналу: 4 МБ"</item>
-    <item msgid="7892098981256010498">"Буфер журналу: 16 МБ"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Вимкнено"</item>
     <item msgid="6014837961827347618">"Усі"</item>
diff --git a/packages/SettingsLib/res/values-ur/arrays.xml b/packages/SettingsLib/res/values-ur/arrays.xml
index f4c2500..a3539ff 100644
--- a/packages/SettingsLib/res/values-ur/arrays.xml
+++ b/packages/SettingsLib/res/values-ur/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">"، فعال (میڈیا)"</item>
     <item msgid="5001852592115448348">"، فعال (فون)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"آف"</item>
-    <item msgid="7839165897132179888">"64K"</item>
-    <item msgid="2715700596495505626">"256K"</item>
-    <item msgid="7099386891713159947">"1M"</item>
-    <item msgid="6069075827077845520">"4M"</item>
-    <item msgid="8243549501764402572">"16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"آف"</item>
     <item msgid="4064786181089783077">"64K"</item>
     <item msgid="3052710745383602630">"256K"</item>
     <item msgid="3691785423374588514">"1M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"آف"</item>
-    <item msgid="4195153527464162486">"‏64K فی لاگ بفر"</item>
-    <item msgid="7464037639415220106">"‏256K فی لاگ بفر"</item>
-    <item msgid="8539423820514360724">"‏1M فی لاگ بفر"</item>
-    <item msgid="1984761927103140651">"‏4M فی لاگ بفر"</item>
-    <item msgid="7892098981256010498">"‏16M فی لاگ بفر"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"آف"</item>
     <item msgid="6014837961827347618">"تمام"</item>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 9376bdc..82783b3 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -576,8 +576,7 @@
     <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+‎"</string>
     <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+‎"</string>
-    <!-- no translation found for data_connection_carrier_wifi (2250268321065848954) -->
-    <skip />
+    <string name="data_connection_carrier_wifi" msgid="2250268321065848954">"CWF"</string>
     <string name="cell_data_off_content_description" msgid="2280700839891636498">"موبائل ڈیٹا آف ہے"</string>
     <string name="not_default_data_content_description" msgid="6517068332106592887">"ڈیٹا استعمال کرنے کے لیے سیٹ نہیں ہے"</string>
     <string name="accessibility_no_phone" msgid="2687419663127582503">"کوئی فون نہیں ہے۔"</string>
diff --git a/packages/SettingsLib/res/values-uz/arrays.xml b/packages/SettingsLib/res/values-uz/arrays.xml
index 0770dcc..e695e20 100644
--- a/packages/SettingsLib/res/values-uz/arrays.xml
+++ b/packages/SettingsLib/res/values-uz/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", faol (media)"</item>
     <item msgid="5001852592115448348">", faol (telefon)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Yoqilmagan"</item>
-    <item msgid="7839165897132179888">"64 KB"</item>
-    <item msgid="2715700596495505626">"256 KB"</item>
-    <item msgid="7099386891713159947">"1 MB"</item>
-    <item msgid="6069075827077845520">"4 MB"</item>
-    <item msgid="8243549501764402572">"16 MB"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Yoqilmagan"</item>
     <item msgid="4064786181089783077">"64 KB"</item>
     <item msgid="3052710745383602630">"256 KB"</item>
     <item msgid="3691785423374588514">"1 MB"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Yoqilmagan"</item>
-    <item msgid="4195153527464162486">"Bufer: maks. 64 KB"</item>
-    <item msgid="7464037639415220106">"Bufer: maks. 256 KB"</item>
-    <item msgid="8539423820514360724">"Bufer: maks. 1 MB"</item>
-    <item msgid="1984761927103140651">"Bufer: maks. 4 MB"</item>
-    <item msgid="7892098981256010498">"Bufer: maks. 16 MB"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Yoqilmagan"</item>
     <item msgid="6014837961827347618">"Hammasi"</item>
diff --git a/packages/SettingsLib/res/values-vi/arrays.xml b/packages/SettingsLib/res/values-vi/arrays.xml
index 635cf11..cac6c46 100644
--- a/packages/SettingsLib/res/values-vi/arrays.xml
+++ b/packages/SettingsLib/res/values-vi/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", đang hoạt động (nội dung nghe nhìn)"</item>
     <item msgid="5001852592115448348">", đang hoạt động (điện thoại)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Tắt"</item>
-    <item msgid="7839165897132179888">"64K"</item>
-    <item msgid="2715700596495505626">"256K"</item>
-    <item msgid="7099386891713159947">"1M"</item>
-    <item msgid="6069075827077845520">"4M"</item>
-    <item msgid="8243549501764402572">"16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Tắt"</item>
     <item msgid="4064786181089783077">"64K"</item>
     <item msgid="3052710745383602630">"256K"</item>
     <item msgid="3691785423374588514">"1M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Tắt"</item>
-    <item msgid="4195153527464162486">"64K mỗi bộ đệm nhật ký"</item>
-    <item msgid="7464037639415220106">"256K mỗi bộ đệm nhật ký"</item>
-    <item msgid="8539423820514360724">"1M mỗi bộ đệm nhật ký"</item>
-    <item msgid="1984761927103140651">"4M mỗi bộ đệm nhật ký"</item>
-    <item msgid="7892098981256010498">"16M mỗi bộ đệm nhật ký"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Tắt"</item>
     <item msgid="6014837961827347618">"Tất cả"</item>
diff --git a/packages/SettingsLib/res/values-zh-rCN/arrays.xml b/packages/SettingsLib/res/values-zh-rCN/arrays.xml
index 29d04e9..dc0ca10 100644
--- a/packages/SettingsLib/res/values-zh-rCN/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">",使用中(媒体)"</item>
     <item msgid="5001852592115448348">",使用中(手机)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"关闭"</item>
-    <item msgid="7839165897132179888">"64K"</item>
-    <item msgid="2715700596495505626">"256K"</item>
-    <item msgid="7099386891713159947">"1M"</item>
-    <item msgid="6069075827077845520">"4M"</item>
-    <item msgid="8243549501764402572">"16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"关闭"</item>
     <item msgid="4064786181089783077">"64K"</item>
     <item msgid="3052710745383602630">"256K"</item>
     <item msgid="3691785423374588514">"1M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"关闭"</item>
-    <item msgid="4195153527464162486">"每个日志缓冲区 64K"</item>
-    <item msgid="7464037639415220106">"每个日志缓冲区 256K"</item>
-    <item msgid="8539423820514360724">"每个日志缓冲区 1M"</item>
-    <item msgid="1984761927103140651">"每个日志缓冲区 4M"</item>
-    <item msgid="7892098981256010498">"每个日志缓冲区 16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"关闭"</item>
     <item msgid="6014837961827347618">"全部"</item>
diff --git a/packages/SettingsLib/res/values-zh-rHK/arrays.xml b/packages/SettingsLib/res/values-zh-rHK/arrays.xml
index e7e2f84..cae08a6 100644
--- a/packages/SettingsLib/res/values-zh-rHK/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">",使用中 (媒體)"</item>
     <item msgid="5001852592115448348">",使用中 (手機)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"關閉"</item>
-    <item msgid="7839165897132179888">"64K"</item>
-    <item msgid="2715700596495505626">"256K"</item>
-    <item msgid="7099386891713159947">"1M"</item>
-    <item msgid="6069075827077845520">"4M"</item>
-    <item msgid="8243549501764402572">"16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"關閉"</item>
     <item msgid="4064786181089783077">"64K"</item>
     <item msgid="3052710745383602630">"256K"</item>
     <item msgid="3691785423374588514">"1M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"關閉"</item>
-    <item msgid="4195153527464162486">"每個記錄緩衝區 64K"</item>
-    <item msgid="7464037639415220106">"每個記錄緩衝區 256K"</item>
-    <item msgid="8539423820514360724">"每個記錄緩衝區 1M"</item>
-    <item msgid="1984761927103140651">"每個記錄緩衝區 4M"</item>
-    <item msgid="7892098981256010498">"每個記錄緩衝區 16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"關閉"</item>
     <item msgid="6014837961827347618">"全部"</item>
diff --git a/packages/SettingsLib/res/values-zh-rTW/arrays.xml b/packages/SettingsLib/res/values-zh-rTW/arrays.xml
index 0fdc14e..959d022 100644
--- a/packages/SettingsLib/res/values-zh-rTW/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">",使用中 (媒體)"</item>
     <item msgid="5001852592115448348">",使用中 (手機)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"關閉"</item>
-    <item msgid="7839165897132179888">"64K"</item>
-    <item msgid="2715700596495505626">"256K"</item>
-    <item msgid="7099386891713159947">"1M"</item>
-    <item msgid="6069075827077845520">"4M"</item>
-    <item msgid="8243549501764402572">"16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"關閉"</item>
     <item msgid="4064786181089783077">"64K"</item>
     <item msgid="3052710745383602630">"256K"</item>
     <item msgid="3691785423374588514">"1M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"關閉"</item>
-    <item msgid="4195153527464162486">"每個記錄緩衝區 64K"</item>
-    <item msgid="7464037639415220106">"每個記錄緩衝區 256K"</item>
-    <item msgid="8539423820514360724">"每個記錄緩衝區 1M"</item>
-    <item msgid="1984761927103140651">"每個記錄緩衝區 4M"</item>
-    <item msgid="7892098981256010498">"每個記錄緩衝區 16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"關閉"</item>
     <item msgid="6014837961827347618">"全部"</item>
diff --git a/packages/SettingsLib/res/values-zu/arrays.xml b/packages/SettingsLib/res/values-zu/arrays.xml
index 2d43c67..78079e8 100644
--- a/packages/SettingsLib/res/values-zu/arrays.xml
+++ b/packages/SettingsLib/res/values-zu/arrays.xml
@@ -155,28 +155,14 @@
     <item msgid="253388653486517049">", iyasebenza (imidiya)"</item>
     <item msgid="5001852592115448348">", iyasebenza (ifoni)"</item>
   </string-array>
-  <string-array name="select_logd_size_titles">
-    <item msgid="1191094707770726722">"Valiwe"</item>
-    <item msgid="7839165897132179888">"64K"</item>
-    <item msgid="2715700596495505626">"256K"</item>
-    <item msgid="7099386891713159947">"1M"</item>
-    <item msgid="6069075827077845520">"4M"</item>
-    <item msgid="8243549501764402572">"16M"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_titles:5 (6078203297886482480) -->
   <string-array name="select_logd_size_lowram_titles">
     <item msgid="1145807928339101085">"Valiwe"</item>
     <item msgid="4064786181089783077">"64K"</item>
     <item msgid="3052710745383602630">"256K"</item>
     <item msgid="3691785423374588514">"1M"</item>
   </string-array>
-  <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"Valiwe"</item>
-    <item msgid="4195153527464162486">"64K ngebhafa yelogu ngayinye"</item>
-    <item msgid="7464037639415220106">"256K ngebhafa yelogu ngayinye"</item>
-    <item msgid="8539423820514360724">"1M ngebhafa yelogu ngayi"</item>
-    <item msgid="1984761927103140651">"4M ngebhafa yelogu ngayinye"</item>
-    <item msgid="7892098981256010498">"16M ngebhafa yelogu ngayinye"</item>
-  </string-array>
+    <!-- no translation found for select_logd_size_summaries:5 (2983219471251787208) -->
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"Valiwe"</item>
     <item msgid="6014837961827347618">"Konke"</item>
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index d278c59..86aa214 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -83,7 +83,7 @@
                         return value == null || value.length() < MAX_LENGTH;
                     }
                 });
-        VALIDATORS.put(System.FONT_SCALE, new InclusiveFloatRangeValidator(0.85f, 1.3f));
+        VALIDATORS.put(System.FONT_SCALE, new InclusiveFloatRangeValidator(0.25f, 5.0f));
         VALIDATORS.put(System.DIM_SCREEN, BOOLEAN_VALIDATOR);
         VALIDATORS.put(
                 System.DISPLAY_COLOR_MODE,
diff --git a/packages/Shell/Android.bp b/packages/Shell/Android.bp
index c873e30..546642d 100644
--- a/packages/Shell/Android.bp
+++ b/packages/Shell/Android.bp
@@ -1,11 +1,15 @@
+// used both for the android_app and android_library
+shell_srcs = ["src/**/*.java",":dumpstate_aidl"]
+shell_static_libs = ["androidx.legacy_legacy-support-v4"]
+
 android_app {
     name: "Shell",
     defaults: ["platform_app_defaults"],
-    srcs: ["src/**/*.java",":dumpstate_aidl"],
+    srcs: shell_srcs,
     aidl: {
         include_dirs: ["frameworks/native/cmds/dumpstate/binder"],
     },
-    static_libs: ["androidx.legacy_legacy-support-v4"],
+    static_libs: shell_static_libs,
     platform_apis: true,
     certificate: "platform",
     privileged: true,
@@ -13,3 +17,18 @@
         include_filter: ["com.android.shell.*"],
     },
 }
+
+// A library for product type like auto to create a new shell package
+// with product specific permissions.
+android_library {
+    name: "Shell-package-library",
+    defaults: ["platform_app_defaults"],
+    srcs: shell_srcs,
+    aidl: {
+        include_dirs: ["frameworks/native/cmds/dumpstate/binder"],
+    },
+    resource_dirs: ["res"],
+    static_libs: shell_static_libs,
+    platform_apis: true,
+    manifest: "AndroidManifest.xml",
+}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 41cc835..859f5a6 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -119,6 +119,7 @@
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
     <uses-permission android:name="android.permission.CREATE_USERS" />
+    <uses-permission android:name="android.permission.MANAGE_CREDENTIAL_MANAGEMENT_APP" />
     <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
     <uses-permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS" />
     <uses-permission android:name="android.permission.ACCESS_LOWPAN_STATE"/>
diff --git a/packages/SystemUI/res-keyguard/drawable/qs_media_seamless_background.xml b/packages/SystemUI/res-keyguard/drawable/qs_media_seamless_background.xml
index 3790378..8e37686 100644
--- a/packages/SystemUI/res-keyguard/drawable/qs_media_seamless_background.xml
+++ b/packages/SystemUI/res-keyguard/drawable/qs_media_seamless_background.xml
@@ -17,9 +17,8 @@
 <ripple xmlns:android="http://schemas.android.com/apk/res/android"
     android:color="@color/media_seamless_border">
     <item android:id="@android:id/background">
-        <shape
-            android:color="@android:color/transparent">
-            <stroke android:width="1dp" android:color="@color/media_seamless_border"/>
+        <shape android:shape="rectangle">
+            <solid android:color="@color/media_seamless_border" />
             <corners android:radius="24dp"/>
         </shape>
     </item>
diff --git a/packages/SystemUI/res/drawable/ic_camera_blocked.xml b/packages/SystemUI/res/drawable/ic_camera_blocked.xml
new file mode 100644
index 0000000..0161bcb
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_camera_blocked.xml
@@ -0,0 +1,29 @@
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24">
+    <path
+        android:pathData="m18,12c-2.75,0 -5,2.25 -5,5 0,2.75 2.25,5 5,5 2.75,0 5,-2.25 5,-5 0,-2.75 -2.1667,-5 -5,-5zM15.5,17.8333h5v-1.6666h-5z"
+        android:fillColor="#30302a"
+        android:fillType="evenOdd"/>
+    <path
+        android:pathData="m16.4,5.5004h-2.536l-1.464,-1.6H7.6l-1.464,1.6H3.6c-0.88,0 -1.6,0.72 -1.6,1.6v9.6c0,0.88 0.72,1.6 1.6,1.6h8.5413C12.0488,17.8817 12,17.4465 12,17c0,-0.1005 0.0025,-0.2004 0.0073,-0.2996H3.6V7.1004H16.4V11.2157C16.9094,11.0751 17.4459,11 18,11V7.1004c0,-0.88 -0.72,-1.6 -1.6,-1.6zM6.8,11.9004c0,-1.768 1.432,-3.2 3.2,-3.2 1.768,0 3.2,1.432 3.2,3.2 0,1.768 -1.432,3.2 -3.2,3.2 -1.768,0 -3.2,-1.432 -3.2,-3.2z"
+        android:fillColor="#30302a"
+        android:fillType="evenOdd"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_mic_blocked.xml b/packages/SystemUI/res/drawable/ic_mic_blocked.xml
new file mode 100644
index 0000000..0ce7a58
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_mic_blocked.xml
@@ -0,0 +1,29 @@
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24">
+    <path
+        android:pathData="m17,12c-2.75,0 -5,2.25 -5,5 0,2.75 2.25,5 5,5 2.75,0 5,-2.25 5,-5 0,-2.75 -2.1667,-5 -5,-5zM14.5,17.8333h5v-1.6666h-5z"
+        android:fillColor="#30302a"
+        android:fillType="evenOdd"/>
+    <path
+        android:pathData="m12,12c0,1.66 -1.34,3 -3,3C7.34,15 6,13.66 6,12L6,6C6,4.34 7.34,3 9,3c1.66,0 3,1.34 3,3zM9,5C8.45,5 8,5.45 8,6v6c0,0.55 0.45,1 1,1 0.55,0 1,-0.45 1,-1L10,6C10,5.45 9.55,5 9,5ZM11.0147,16.577C10.3983,16.849 9.7167,17 9,17 6.24,17 4,14.76 4,12L2,12c0,3.53 2.61,6.43 6,6.92L8,22h2v-3.08c0.4212,-0.0609 0.8303,-0.1589 1.2238,-0.2908C11.078,18.1111 11,17.5647 11,17c0,-0.1422 0.0049,-0.2832 0.0147,-0.423z"
+        android:fillColor="#30302a"
+        android:fillType="evenOdd"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_no_calling_sms.xml b/packages/SystemUI/res/drawable/ic_qs_no_calling_sms.xml
new file mode 100644
index 0000000..0e308d2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_no_calling_sms.xml
@@ -0,0 +1,12 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M20.17,14.84l-3.26,-0.65c-0.33,-0.07 -0.67,0.04 -0.9,0.27l-2.62,2.62c-2.75,-1.49 -5.01,-3.75 -6.5,-6.5l2.62,-2.62c0.24,-0.24 0.34,-0.58 0.27,-0.9L9.13,3.8C9.04,3.34 8.63,3 8.15,3H4C3.44,3 2.97,3.47 3,4.03c0.17,2.91 1.04,5.63 2.43,8.01c1.57,2.69 3.81,4.93 6.5,6.5c2.38,1.39 5.1,2.26 8.01,2.43c0.56,0.03 1.03,-0.44 1.03,-1v-4.15C20.97,15.34 20.64,14.93 20.17,14.84z"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M22,3.41L20.59,2L18.5,4.09L16.41,2L15,3.41l2.09,2.09L15,7.59L16.41,9l2.09,-2.08L20.59,9L22,7.59L19.92,5.5L22,3.41z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/qs_media_background.xml b/packages/SystemUI/res/drawable/qs_media_background.xml
index 656d2e4..6ed3a0ae 100644
--- a/packages/SystemUI/res/drawable/qs_media_background.xml
+++ b/packages/SystemUI/res/drawable/qs_media_background.xml
@@ -17,4 +17,4 @@
 <com.android.systemui.media.IlluminationDrawable
     xmlns:systemui="http://schemas.android.com/apk/res-auto"
     systemui:highlight="15"
-    systemui:cornerRadius="?android:attr/dialogCornerRadius" />
\ No newline at end of file
+    systemui:cornerRadius="@dimen/notification_corner_radius" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/media_view.xml b/packages/SystemUI/res/layout/media_view.xml
index 170f2c4..6b42705 100644
--- a/packages/SystemUI/res/layout/media_view.xml
+++ b/packages/SystemUI/res/layout/media_view.xml
@@ -64,7 +64,7 @@
     </FrameLayout>
 
     <!--  Actions must be ordered left-to-right even in RTL layout.  However, they appear in a chain
-    with the album art and the title, and must as a group appear at the end of that chain.  This is
+    with the album art, and must as a group appear at the end of that chain.  This is
     accomplished by having all actions appear in a LTR chain within the parent, and then biasing it
     to the right side, then this barrier is used to bound the text views.  -->
     <androidx.constraintlayout.widget.Barrier
@@ -72,10 +72,10 @@
         android:layout_width="0dp"
         android:layout_height="0dp"
         android:orientation="vertical"
-        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/header_artist"
         app:barrierDirection="start"
         app:constraint_referenced_ids="action0,action1,action2,action3,action4"
-        />
+        app:layout_constraintHorizontal_bias="0" />
 
     <ImageButton
         android:id="@+id/action0"
@@ -111,42 +111,46 @@
     <ImageView
         android:id="@+id/album_art"
         android:layout_width="@dimen/qs_media_album_size"
-        android:layout_height="@dimen/qs_media_album_size" />
+        android:layout_height="@dimen/qs_media_album_size"
+        android:layout_gravity="center_vertical" />
 
     <!-- Seamless Output Switcher -->
     <LinearLayout
         android:id="@+id/media_seamless"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
-        android:foreground="@drawable/qs_media_seamless_background"
-        android:background="@drawable/qs_media_light_source"
         android:orientation="horizontal"
-        android:forceHasOverlappingRendering="false"
-        android:paddingStart="12dp"
-        android:paddingTop="6dp"
-        android:paddingEnd="12dp"
-        android:paddingBottom="6dp">
-
-        <ImageView
-            android:id="@+id/media_seamless_image"
-            android:layout_width="@dimen/qs_seamless_icon_size"
-            android:layout_height="@dimen/qs_seamless_icon_size"
-            android:layout_marginEnd="8dp"
-            android:layout_gravity="center_vertical"
-            android:tint="@color/media_primary_text"
-            android:src="@*android:drawable/ic_media_seamless" />
-
-        <TextView
-            android:id="@+id/media_seamless_text"
+        android:gravity="center_vertical|end"
+        android:forceHasOverlappingRendering="false">
+        <LinearLayout
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_gravity="center_vertical"
-            android:fontFamily="@*android:string/config_headlineFontFamily"
-            android:singleLine="true"
-            android:text="@*android:string/ext_media_seamless_action"
-            android:textColor="@color/media_primary_text"
-            android:textDirection="locale"
-            android:textSize="14sp" />
+            android:foreground="@drawable/qs_media_seamless_background"
+            android:background="@drawable/qs_media_light_source"
+            android:orientation="horizontal"
+            android:padding="6dp"
+            android:contentDescription="@string/quick_settings_media_device_label">
+            <ImageView
+                android:id="@+id/media_seamless_image"
+                android:layout_width="@dimen/qs_seamless_icon_size"
+                android:layout_height="@dimen/qs_seamless_icon_size"
+                android:layout_gravity="center"
+                android:tint="@color/media_primary_text"
+                android:src="@*android:drawable/ic_media_seamless" />
+            <TextView
+                android:visibility="gone"
+                android:id="@+id/media_seamless_text"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical"
+                android:layout_marginStart="8dp"
+                android:fontFamily="@*android:string/config_headlineFontFamily"
+                android:singleLine="true"
+                android:text="@*android:string/ext_media_seamless_action"
+                android:textColor="@color/media_primary_text"
+                android:textDirection="locale"
+                android:textSize="14sp" />
+        </LinearLayout>
     </LinearLayout>
 
     <ImageView
@@ -206,8 +210,9 @@
     <com.android.internal.widget.CachingIconView
         android:id="@+id/icon"
         android:tint="@color/media_primary_text"
-        android:layout_width="@dimen/qs_media_icon_size"
-        android:layout_height="@dimen/qs_media_icon_size" />
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_margin="6dp" />
 
     <!-- Constraints are set here as they are the same regardless of host -->
     <TextView
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 317e0e8..ba39d1e 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Invoermetode"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Ligging"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Ligging af"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Mediatoestel"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Net noodoproepe"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index b7b24db..a193bbb 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"የግቤት ስልት"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"አካባቢ"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"አካባቢ ጠፍቷል"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"የሚዲያ መሣሪያ"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"የአደጋ ጊዜ ጥሪዎች ብቻ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index ca823ed..a634281dc 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -348,6 +348,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"أسلوب الإدخال"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"الموقع الجغرافي"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"الموقع قيد الإيقاف"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"جهاز الوسائط"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"مكالمات طوارئ فقط"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 8e6fd51..1151644 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"ইনপুট পদ্ধতি"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"অৱস্থান"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"অৱস্থান অফ"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"মিডিয়া ডিভাইচ"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"জৰুৰীকালীন কল মাত্ৰ"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index d9a2ae1..146add2f 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Daxiletmə metodu"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Yer"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Yer Deaktiv"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Media cihazı"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Yalnız təcili zənglər"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index ef3a1cf..77b101c 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -345,6 +345,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Metod unosa"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Lokacija"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Lokacija je isključena"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Medijski uređaj"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Samo hitni pozivi"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index a1804d1..5977d04 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -346,6 +346,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Метад уводу"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Месцазнаходжанне"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Вызначэнне месцазнаходжання адключана"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Мультымедыйная прылада"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Толькі экстранныя выклікі"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 6b59b24..53eeac8 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Метод на въвеждане"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Местоположение"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Местоположението е изключено"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Мултимедийно устройство"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"Индикатор за силата на получения сигнал (RSSI)"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Само спешни обаждания"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index a6344d0..b944dde 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"ইনপুট পদ্ধতি"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"লোকেশন"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"লোকেশন বন্ধ করা আছে"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"মিডিয়া ডিভাইস"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"শুধুমাত্র জরুরি কল"</string>
@@ -354,12 +358,9 @@
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"নতুন ব্যবহারকারী"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"ওয়াই-ফাই"</string>
     <string name="quick_settings_internet_label" msgid="6603068555872455463">"ইন্টারনেট"</string>
-    <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
-    <skip />
+    <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"বিমানের জন্য নিরাপদ"</string>
+    <string name="quick_settings_networks_available" msgid="1875138606855420438">"নেটওয়ার্ক উপলভ্য"</string>
+    <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"নেটওয়ার্ক উপলভ্য নেই"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"সংযুক্ত নয়"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"কোনো নেটওয়ার্ক নেই"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"ওয়াই-ফাই বন্ধ"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 0dc97fa..7717c65 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -345,6 +345,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Način unosa"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Lokacija"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Utvrđivanje lokacije isključeno"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Medijski uređaj"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Samo pozivi za hitne slučajeve"</string>
@@ -355,12 +359,9 @@
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Novi korisnik"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"WiFi"</string>
     <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
-    <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
-    <skip />
+    <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Sigurno za rad u zrakoplovu"</string>
+    <string name="quick_settings_networks_available" msgid="1875138606855420438">"Mreže su dostupne"</string>
+    <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Mreže nisu dostupne"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nije povezano"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Nema mreže"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"WiFi je isključen"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index bd5815a6..f648bc6 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Mètode d\'introducció"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Ubicació"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Ubicació desactivada"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Dispositiu multimèdia"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Només trucades d\'emergència"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 41a33ef..4d14d2b 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -346,6 +346,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Metoda zadávání dat"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Poloha"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Poloha vypnuta"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Mediální zařízení"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Pouze tísňová volání"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 3d8b027..95b1a55 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Inputmetode"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Placering"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Placering fra"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Medieenhed"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Kun nødopkald"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index a0e535f..e6acd87 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Eingabemethode"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Standort"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Standort aus"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Mediengerät"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Nur Notrufe"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 13dafa0..867c7d2 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Μέθοδος εισαγωγής"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Τοποθεσία"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Τοποθεσία απενεργοποιημένη"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Συσκευή μέσων"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Μόνο κλήσεις έκτακτης ανάγκης"</string>
@@ -354,12 +358,9 @@
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Νέος χρήστης"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
     <string name="quick_settings_internet_label" msgid="6603068555872455463">"Διαδίκτυο"</string>
-    <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
-    <skip />
+    <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Ασφαλές για πτήση"</string>
+    <string name="quick_settings_networks_available" msgid="1875138606855420438">"Υπάρχουν διαθέσιμα δίκτυα"</string>
+    <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Δεν υπάρχουν διαθέσιμα δίκτυα"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Μη συνδεδεμένο"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Κανένα δίκτυο"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi ανενεργό"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index dcee89d..185af57 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Input Method"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Location Off"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Media device"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Emergency Calls Only"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 3217d1c..3517f87 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Input Method"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Location Off"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Media device"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Emergency Calls Only"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index dcee89d..185af57 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Input Method"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Location Off"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Media device"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Emergency Calls Only"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index dcee89d..185af57 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Input Method"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Location Off"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Media device"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Emergency Calls Only"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 00fa584..306116c 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‎‏‎‎‎‎‎‎‏‏‏‎‎‎‎‏‏‏‏‎‏‏‎‎‏‏‏‎‏‏‎‎‎‎‏‎‎‏‎‎‎‏‏‎‏‏‎‎‏‎‎‎‏‎‎‏‏‎Input Method‎‏‎‎‏‎"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‏‎‎‎‏‎‏‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‏‏‏‎‎‎‏‏‎‏‎‎‏‏‏‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎Location‎‏‎‎‏‎"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‏‎‏‏‏‎‏‏‏‎‎‏‏‏‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‏‎‏‎‏‏‎‎‎‏‏‎‎‏‎‎‎‏‏‏‏‎Location Off‎‏‎‎‏‎"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‏‏‏‎‏‏‏‏‎‏‎‏‎‎‏‏‏‎‏‏‏‏‏‏‎‎‏‎‎‎‏‎‎‏‏‏‎‏‎‏‎Media device‎‏‎‎‏‎"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‏‎‎‏‏‎‏‏‎‎‎‎‎‏‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‏‎‎‎‏‎‎‏‎‎‏‎‏‏‏‎‏‎RSSI‎‏‎‎‏‎"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‎‎‏‎‏‎‎‎‏‎‎‏‎‎‏‏‏‎‏‎‏‏‎‏‎‎‏‎‏‏‏‎‏‎‏‏‏‏‎‏‏‏‎‏‎‏‎‎‎‏‏‎‎Emergency Calls Only‎‏‎‎‏‎"</string>
@@ -354,12 +358,9 @@
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‎‎‏‏‏‎‏‏‎‎‎‏‎‎‏‏‎‏‎‏‎‎‏‏‎‏‏‏‎‏‎‏‎‎‏‏‎‏‏‏‎‎‏‎‏‏‎‏‎‎‎‏‎‎‎‏‎‎New user‎‏‎‎‏‎"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‎‎‎‏‏‎‏‏‎‎‎‎‏‎‎‏‏‏‏‏‎‎‎‏‎‏‎‏‏‎‎‏‎‏‏‎‎‎‎‏‏‎‎‎Wi-Fi‎‏‎‎‏‎"</string>
     <string name="quick_settings_internet_label" msgid="6603068555872455463">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‎‎‏‎‏‏‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‏‏‏‎‏‎‎‎‏‎‏‎‏‎‎‎‏‎‎‏‎‏‏‎‎‏‎‎‏‏‏‎Internet‎‏‎‎‏‎"</string>
-    <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
-    <skip />
+    <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‎‏‎‎‎‏‎‎‏‎‏‎‎‏‎‎‎‎‎‏‏‏‎‎‏‏‎‏‎‎‏‎‎‎‎‎‏‎‏‏‎Airplane-safe‎‏‎‎‏‎"</string>
+    <string name="quick_settings_networks_available" msgid="1875138606855420438">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‎‎‎‎‎‏‎‏‏‏‎‏‎‏‎‎‏‎‏‎‎‎‎‎‏‏‎‎‎‏‏‎‎‎‏‏‏‏‎‎‏‏‏‏‏‎‏‎‎‎‎‏‎‏‏‎‎Networks available‎‏‎‎‏‎"</string>
+    <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‎‏‏‎‏‎‏‎‎‎‎‎‏‏‎‏‎‏‎‏‎‏‏‏‏‎‎‏‏‏‎‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‎‎‏‏‏‎‎‏‎‎Networks unavailable‎‏‎‎‏‎"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‏‎‏‎‎‎‎‎‏‎‎‎‎‏‏‎‎‎‏‏‏‏‎‎‏‎‎‎‏‏‎‏‏‎‏‏‏‎‎‎‎Not Connected‎‏‎‎‏‎"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‎‎‏‏‏‏‏‎‎‏‎‎‏‎‏‏‏‏‎‎‏‎‏‎‎‎‏‎‏‎‏‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎No Network‎‏‎‎‏‎"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‎‏‏‏‎‏‏‎‏‏‏‎‎‏‎‏‎‏‎‎‎‏‏‎‎‎‎‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‏‏‏‎‎‎‎‏‎‏‎‎Wi-Fi Off‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index a552c76..27c424b 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Método de introducción"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Ubicación"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Ubicación desactivada"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Dispositivo multimedia"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Solo emergencia"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 4277c63..ab5d0d2 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Método de entrada"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Ubicación"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Ubicación desactivada"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Dispositivo multimedia"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Solo llamadas de emergencia"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 6429931..6c7e19a 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Sisestusmeetod"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Asukoht"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Asukoht on väljas"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Meediaseade"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Ainult hädaabikõned"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 664ae98..da7733c 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Idazketa-metodoa"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Kokapena"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Kokapena desaktibatuta"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Multimedia-gailua"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Larrialdi-deiak soilik"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 578fe88..2bc2e57 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"روش ورودی"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"مکان"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"مکان خاموش"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"دستگاه رسانه"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"فقط تماس‌های اضطراری"</string>
@@ -354,12 +358,9 @@
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"کاربر جدید"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
     <string name="quick_settings_internet_label" msgid="6603068555872455463">"اینترنت"</string>
-    <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
-    <skip />
+    <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"ایمن در هواپیما"</string>
+    <string name="quick_settings_networks_available" msgid="1875138606855420438">"شبکه دردسترس است"</string>
+    <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"شبکه دردسترس نیست"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"متصل نیست"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"شبکه‌ای موجود نیست"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"‏Wi-Fi خاموش است"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index d73b2eb..28708b9 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Syöttötapa"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Sijainti"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Sijainti ei käytössä"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Medialaite"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Vain hätäpuhelut"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index df0e36c..8235638 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Mode de saisie"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Position"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Localisation désactivée"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Appareil multimédia"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Appels d\'urgence uniquement"</string>
@@ -354,12 +358,9 @@
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nouvel utilisateur"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
     <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
-    <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
-    <skip />
+    <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Sécuritaire pour les avions"</string>
+    <string name="quick_settings_networks_available" msgid="1875138606855420438">"Réseaux accessibles"</string>
+    <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Aucun réseau accessible"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Non connecté"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Aucun réseau"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi désactivé"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 64a2328..50a3cfb 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Mode de saisie"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Localisation"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Localisation désactivée"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Appareil multimédia"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Appels d\'urgence"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 75db845..4c6a53e 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Método de introdución de texto"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Localización"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Localización desactivada"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Dispositivo multimedia"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Só chamadas de emerxencia"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index c0d2557..add1ef5 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"ઇનપુટ પદ્ધતિ"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"સ્થાન"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"સ્થાન બંધ"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"મીડિયા ઉપકરણ"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"ફક્ત ઇમર્જન્સી કૉલ"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 0bfa5ae..b4d61bb 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -346,6 +346,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"इनपुट विधि"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"जगह"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"जगह की जानकारी बंद है"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"मीडिया डिवाइस"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"सिर्फ़ आपातकालीन कॉल"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 33d0534..e5cf20a 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -345,6 +345,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Način unosa"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Lokacija"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Lokacija je isključena"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Medijski uređaj"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Samo hitni pozivi"</string>
@@ -355,12 +359,9 @@
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Novi korisnik"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
     <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
-    <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
-    <skip />
+    <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Sigurno za rad u zrakoplovu"</string>
+    <string name="quick_settings_networks_available" msgid="1875138606855420438">"Mreže su dostupne"</string>
+    <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Mreže nisu dostupne"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nije povezano"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Nema mreže"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi isključen"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 22b8fde..958e25f6 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Beviteli módszer"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Tartózkodási hely"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Hely kikapcsolva"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Médiaeszköz"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Csak segélyhívások"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 5e51c62..4fd1abe 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Մուտքագրման եղանակը"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Տեղորոշում"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Անջատել տեղադրությունը"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Մեդիա սարք"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Միայն շտապ կանչեր"</string>
@@ -354,12 +358,9 @@
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Նոր օգտատեր"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
     <string name="quick_settings_internet_label" msgid="6603068555872455463">"Ինտերնետ"</string>
-    <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
-    <skip />
+    <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Ցանցեր, որոնք անվտանգ են ինքնաթիռում"</string>
+    <string name="quick_settings_networks_available" msgid="1875138606855420438">"Հասանելի ցանցեր"</string>
+    <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Անհասանելի ցանցեր"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Միացված չէ"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ցանց չկա"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi-ը անջատված է"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 9a217ce..4136ead 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Metode Masukan"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Lokasi"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Lokasi Nonaktif"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Perangkat media"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Panggilan Darurat Saja"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 3f8e8fb..15c07e4 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Innsláttaraðferð"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Staðsetning"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Staðsetning óvirk"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Margmiðlunartæki"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Aðeins neyðarsímtöl"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 72cc5aa..299824b 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Metodo di immissione"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Geolocalizzazione"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Geolocalizz. non attiva"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Dispositivo multimediale"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Solo chiamate di emergenza"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index d8c148a..e8cc8bf 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -346,6 +346,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"שיטת קלט"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"מיקום"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"מיקום כבוי"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"מכשיר מדיה"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"שיחות חירום בלבד"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 40a9323..459b520 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"入力方法"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"位置情報"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"現在地OFF"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"メディアデバイス"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"緊急通報のみ"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 6ab5510..20f2d03 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"შეყვანის მეთოდი"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"მდებარეობა"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"მდებარეობა გამორთულია"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"მედია მოწყობილობა"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"მხოლოდ გადაუდებელი დახმარების ზარებისთვის"</string>
@@ -354,12 +358,9 @@
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"ახალი მომხმარებელი"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
     <string name="quick_settings_internet_label" msgid="6603068555872455463">"ინტერნეტი"</string>
-    <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
-    <skip />
+    <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"თვითმფრინავისთვის უსაფრთხო"</string>
+    <string name="quick_settings_networks_available" msgid="1875138606855420438">"ქსელები ხელმისაწვდომია"</string>
+    <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"ქსელები მიუწვდომელია"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"არ არის დაკავშირებული."</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"ქსელი არ არის"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi გამორთულია"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index bda2f1a..65f3032 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Енгізу әдісі"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Орналасу"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Орын өшірулі"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Meдиа құрылғысы"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI (алынған сигнал қуатының көрсеткіші)"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Құтқару қызметіне ғана қоңырау шалынады"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 275a73a..a4f6e0a 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"វិធីសាស្ត្រ​បញ្ចូល"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"ទី​តាំង​"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"ទីតាំង​បាន​បិទ"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"ឧបករណ៍​មេឌៀ"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"ការហៅទៅលេខសង្គ្រោះបន្ទាន់​តែប៉ុណ្ណោះ"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 778ccca..e02ed5a 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"ಇನ್‌ಪುಟ್ ವಿಧಾನ"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"ಸ್ಥಳ"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"ಸ್ಥಳ ಆಫ್ ಆಗಿದೆ"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"ಮಾಧ್ಯಮ ಸಾಧನ"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"ತುರ್ತು ಕರೆಗಳು ಮಾತ್ರ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index e602ede..e9d33fa 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"입력 방법"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"위치"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"위치 사용 중지"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"미디어 기기"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"긴급 통화만 허용"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 0a2e8ae..f4191d4 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -346,6 +346,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Киргизүү ыкмасы"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Жайгашкан жер"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Жайгашытрууну өчүрүү"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Медиа түзмөгү"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Кырсыктаганда гана чалуу"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 0f320a5..0f0236f 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"ວິທີການປ້ອນຂໍ້ມູນ"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"ສະຖານທີ່"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"ຂໍ້ມູນສະຖານທີ່ປິດຢູ່"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"ອຸປະກອນສື່"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"ໂທສຸກເສີນເທົ່ານັ້ນ"</string>
@@ -354,12 +358,9 @@
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"ຜູ່ໃຊ້ໃໝ່"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi​-Fi"</string>
     <string name="quick_settings_internet_label" msgid="6603068555872455463">"ອິນເຕີເນັດ"</string>
-    <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
-    <skip />
+    <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"ປອດໄພກັບໃນຍົນ"</string>
+    <string name="quick_settings_networks_available" msgid="1875138606855420438">"ມີເຄືອຂ່າຍທີ່ສາມາດໃຊ້ໄດ້"</string>
+    <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"ບໍ່ມີເຄືອຂ່າຍທີ່ສາມາດໃຊ້ໄດ້"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"ບໍ່ໄດ້ເຊື່ອມຕໍ່"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"ບໍ່ມີເຄືອຂ່າຍ"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi​-Fi ປິດ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 29f615e..8d9051d 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -346,6 +346,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Įvesties metodas"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Vietovė"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Vietovė išjungta"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Medijos įrenginys"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Tik skambučiai pagalbos numeriu"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index f209ba8..1cde532 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -345,6 +345,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Ievades metode"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Atrašanās vieta"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Atrašanās vieta izslēgta"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Multivides ierīce"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Tikai ārkārtas izsaukumi"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 001e6a0..a006bc9 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Метод на внес"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Локација"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Исклучи локација"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Медиумски уред"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Само итни повици"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index e2ca3bb..4d2898f 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"ടൈപ്പുചെയ്യൽ രീതി"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"ലൊക്കേഷൻ"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"ലൊക്കേഷൻ ഓഫാണ്"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"മീഡിയ ഉപകരണം"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"അടിയന്തിര കോളുകൾ മാത്രം"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 0b1a1ff..8845b07 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Оруулах арга"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Байршил"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Байршил идэвхгүй"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Медиа төхөөрөмж"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Зөвхөн яаралтай дуудлага"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 9ed6bb3..48498b7 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"इनपुट पद्धत"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"स्थान"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"स्थान बंद"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"मीडिया डिव्हाइस"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"फक्त आणीबाणीचे कॉल"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 81c15b0..4204417 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Kaedah Input"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Lokasi"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Lokasi Dimatikan"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Peranti media"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Panggilan Kecemasan Sahaja"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 6bccb33..9b7488e 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"ထည့်သွင်းရန်နည်းလမ်း"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"တည်နေရာ"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"တည်နေရာပြမှု မရှိ"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"မီဒီယာ စက်ပစ္စည်း"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"အရေးပေါ်ခေါ်ဆိုမှုများသာ"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 90defaa..490ba99 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Inndatametode"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Sted"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Posisjon av"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Medieenhet"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Bare nødanrop"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 0e86b94..cf267fd 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"आगत विधि"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"स्थान"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"स्थान बन्द छ"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"मिडिया उपकरण"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"आपत्‌कालीन कल मात्र"</string>
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index 672d2f6..c4cf440 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -73,7 +73,7 @@
     <color name="media_divider">#85ffffff</color>
 
     <!-- Biometric dialog colors -->
-    <color name="biometric_dialog_gray">#ff888888</color>
+    <color name="biometric_dialog_gray">#ffcccccc</color>
     <color name="biometric_dialog_accent">#ff80cbc4</color> <!-- light teal -->
     <color name="biometric_dialog_error">#fff28b82</color> <!-- red 300 -->
 
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index a216c49..ddb9abc 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Invoermethode"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Locatie"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Locatie uit"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Media-apparaat"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Alleen noodoproepen"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index ed38d14..ce6723e 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"ଇନପୁଟ୍ ପଦ୍ଧତି"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"ଲୋକେସନ୍‍"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"ଲୋକେସନ୍‍ ଅଫ୍‍"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"ମିଡିଆ ଡିଭାଇସ୍‌"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"କେବଳ ଜରୁରୀକାଳୀନ କଲ୍‌"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 3026a18..ad40d6c 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"ਇਨਪੁੱਟ ਵਿਧੀ"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"ਟਿਕਾਣਾ"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਬੰਦ"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"ਮੀਡੀਆ ਡੀਵਾਈਸ"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"ਸਿਰਫ਼ ਸੰਕਟਕਾਲੀਨ ਕਾਲਾਂ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 12422e9..75abfda 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -346,6 +346,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Metoda wprowadzania"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Lokalizacja"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Lokalizacja wyłączona"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Urządzenie multimedialne"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Tylko połączenia alarmowe"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 0d65c01..1ab1002 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Método de entrada"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Localização"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Localização desativada"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Dispositivo de mídia"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Chamadas de emergência"</string>
@@ -354,12 +358,9 @@
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Novo usuário"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
     <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
-    <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
-    <skip />
+    <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Segura para aviões"</string>
+    <string name="quick_settings_networks_available" msgid="1875138606855420438">"Redes disponíveis"</string>
+    <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Redes indisponíveis"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Não conectado"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Sem rede"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi desligado"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 0932a96..06b67fb 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Método de Introdução"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Localização"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Localização Desativada"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Dispositivo multimédia"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Apenas chamadas de emergência"</string>
@@ -354,12 +358,9 @@
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Novo utilizador"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
     <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
-    <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
-    <skip />
+    <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Seguras para aviões"</string>
+    <string name="quick_settings_networks_available" msgid="1875138606855420438">"Redes disponíveis"</string>
+    <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Redes indisponíveis"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Não Ligado"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Sem Rede"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi Desligado"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 0d65c01..1ab1002 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Método de entrada"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Localização"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Localização desativada"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Dispositivo de mídia"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Chamadas de emergência"</string>
@@ -354,12 +358,9 @@
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Novo usuário"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
     <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
-    <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
-    <skip />
+    <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Segura para aviões"</string>
+    <string name="quick_settings_networks_available" msgid="1875138606855420438">"Redes disponíveis"</string>
+    <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Redes indisponíveis"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Não conectado"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Sem rede"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi desligado"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index e181945..54d53af 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -345,6 +345,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Metodă de introducere"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Locație"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Localizarea este dezactivată"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Dispozitiv media"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Numai apeluri de urgență"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 5d08e3a..b6c2812 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -346,6 +346,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Способ ввода"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Геолокация"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Местоположение выкл."</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Режим медиа"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Экстр. вызов"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 7230a06..c1ba12b 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"ආදාන ක්‍රමය"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"ස්ථානය"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"ස්ථානය අක්‍රියයි"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"මාධ්‍ය උපාංගය"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"හදිසි ඇමතුම් පමණි"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 1454884..dfa371b 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -346,6 +346,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Metóda vstupu"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Poloha"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Poloha vypnutá"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Mediálne zariadenie"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Len tiesňové volania"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 2cecff7..5f5ee65 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -346,6 +346,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Način vnosa"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Lokacija"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Lokacija izklopljena"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Predstavnostna naprava"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Le klici v sili"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 3179e99..e1ca274 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Metoda e hyrjes"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Vendndodhja"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Vendndodhja është e çaktivizuar"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Pajisje e jashtme ruajtëse"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Vetëm telefonata urgjence"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index ea862bc..d7bc5a1 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -345,6 +345,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Метод уноса"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Локација"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Локација је искључена"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Медијски уређај"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Само хитни позиви"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 66685e9..3e38bdd 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Inmatningsmetod"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Plats"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Plats har inaktiverats"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Medieenhet"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Endast nödsamtal"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 1563c76..5d1698d 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Mbinu ya uingizaji"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Kutambua Mahali"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Kitambua eneo kimezimwa"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Kifaa cha faili"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Simu za Dharura Pekee"</string>
@@ -354,12 +358,9 @@
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Mtumiaji mpya"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
     <string name="quick_settings_internet_label" msgid="6603068555872455463">"Intaneti"</string>
-    <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
-    <skip />
+    <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Hali salama ya ndegeni"</string>
+    <string name="quick_settings_networks_available" msgid="1875138606855420438">"Mitandao inapatikana"</string>
+    <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Mitandao haipatikani"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Haijaunganishwa"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Hakuna Mtandao"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi Imezimwa"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index a54b1a2..ebb7fa6 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"உள்ளீட்டு முறை"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"இருப்பிடம்"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"இருப்பிடத்தை முடக்கு"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"மீடியா சாதனம்"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"அவசரகால அழைப்புகள் மட்டும்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 01c3d7d1..1456a8c 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"ఇన్‌పుట్ పద్ధతి"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"లొకేషన్"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"లొకేష‌న్ ఆఫ్‌లో ఉంది"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"ప్రసార మాధ్యమ పరికరం"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"ఎమర్జెన్సీ కాల్స్ మాత్రమే"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index e51c308..65ee106 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"วิธีป้อนข้อมูล"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"ตำแหน่ง"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"ปิดตำแหน่ง"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"อุปกรณ์สื่อ"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"โทรฉุกเฉินเท่านั้น"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 7b8070b..9eab088 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Pamamaraan ng Pag-input"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Lokasyon"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Naka-off ang Lokasyon"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Device ng media"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Mga Pang-emergency na Tawag Lamang"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index f9e78c7..921cce8 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Giriş Yöntemi"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Konum"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Konum Bilgisi Kapalı"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Medya cihazı"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Yalnızca Acil Çağrılar İçin"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 72046e1..66a8cfb 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -346,6 +346,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Метод введення"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Місцезнаходження"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Місцезнаходження вимкнено"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Носій"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Екстрені виклики"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 9ccc133..3865bc0 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"ان پٹ کا طریقہ"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"مقام"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"مقام آف"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"میڈیا آلہ"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"صرف ہنگامی کالیں"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 67d801b4..d6061a6 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Kiritish usuli"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Joylashuv"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Joylashuvni aniqlash xizmati yoqilmagan"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Media qurilma"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Favqulodda chaqiruvlar"</string>
@@ -354,12 +358,9 @@
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Yangi foydalanuvchi"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
     <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
-    <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
-    <skip />
-    <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
-    <skip />
+    <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Samolyot uchun xavfsiz"</string>
+    <string name="quick_settings_networks_available" msgid="1875138606855420438">"Tarmoqlar mavjud"</string>
+    <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Tarmoqqa ulanish imkonsiz"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Ulanmagan"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Tarmoq mavjud emas"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi o‘chiq"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 1d836e8..23e72c1 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Phương thức nhập"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Vị trí"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Tắt vị trí"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Thiết bị phương tiện"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Chỉ cuộc gọi khẩn cấp"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index fa6a510..55b524e 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"输入法"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"位置信息"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"位置信息:关闭"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"媒体设备"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"只能拨打紧急呼救电话"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index b69d097..701f32d 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"輸入法"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"位置"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"位置資訊已關閉"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"媒體裝置"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"只可撥打緊急電話"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 2fb0b86..4210ec1 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"輸入法"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"定位"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"定位服務已關閉"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"媒體裝置"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"僅可撥打緊急電話"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index e9e1a75..940fc19 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -344,6 +344,10 @@
     <string name="quick_settings_ime_label" msgid="3351174938144332051">"Indlela yokungenayo"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Indawo"</string>
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Indawo ivaliwe"</string>
+    <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
+    <skip />
+    <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
+    <skip />
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Idivayisi yemidiya"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Amakholi aphuthumayo kuphela"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 101124e..93d2f75 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
+        wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,dark,work,cast,night,screenrecord,reverse,reduce_brightness,cameratoggle,mictoggle
     </string>
 
     <!-- The tiles to display in QuickSettings -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 72dd724..d104d17 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -619,7 +619,7 @@
     <dimen name="z_distance_between_notifications">0.5dp</dimen>
 
     <!-- The height of the divider between the individual notifications. -->
-    <dimen name="notification_divider_height">4dp</dimen>
+    <dimen name="notification_divider_height">2dp</dimen>
 
     <!-- The corner radius of the shadow behind the notification. -->
     <dimen name="notification_shadow_radius">0dp</dimen>
@@ -1180,10 +1180,9 @@
     <dimen name="new_qs_vertical_margin">8dp</dimen>
 
     <!-- Size of media cards in the QSPanel carousel -->
-    <dimen name="qs_media_width">350dp</dimen>
     <dimen name="qs_media_padding">16dp</dimen>
     <dimen name="qs_media_panel_outer_padding">16dp</dimen>
-    <dimen name="qs_media_album_size">52dp</dimen>
+    <dimen name="qs_media_album_size">120dp</dimen>
     <dimen name="qs_media_icon_size">16dp</dimen>
     <dimen name="qs_center_guideline_padding">10dp</dimen>
     <dimen name="qs_seamless_icon_size">@dimen/qs_media_icon_size</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 7cdd8b1..ac2e342 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -821,6 +821,10 @@
     <string name="quick_settings_location_label">Location</string>
     <!-- QuickSettings: Location (Off) [CHAR LIMIT=NONE] -->
     <string name="quick_settings_location_off_label">Location Off</string>
+    <!-- QuickSettings: Camera [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_camera_label">Block Camera</string>
+    <!-- QuickSettings: Microphone [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_mic_label">Mute Microphone</string>
     <!-- QuickSettings: Media device [CHAR LIMIT=NONE] -->
     <string name="quick_settings_media_device_label">Media device</string>
     <!-- QuickSettings: RSSI [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/res/xml/media_collapsed.xml b/packages/SystemUI/res/xml/media_collapsed.xml
index ee958f2..f834d6d 100644
--- a/packages/SystemUI/res/xml/media_collapsed.xml
+++ b/packages/SystemUI/res/xml/media_collapsed.xml
@@ -22,36 +22,39 @@
         android:layout_width="@dimen/qs_media_icon_size"
         android:layout_height="@dimen/qs_media_icon_size"
         android:layout_marginStart="18dp"
-        app:layout_constraintTop_toTopOf="@id/app_name"
-        app:layout_constraintBottom_toBottomOf="@id/app_name"
-        app:layout_constraintStart_toStartOf="parent"
+        android:layout_marginTop="@dimen/qs_media_panel_outer_padding"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintStart_toEndOf="@id/album_art"
         />
 
     <Constraint
         android:id="@+id/app_name"
-        android:layout_width="0dp"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginEnd="@dimen/qs_center_guideline_padding"
-        android:layout_marginStart="10dp"
-        android:layout_marginTop="20dp"
-        app:layout_constraintTop_toTopOf="parent"
+        android:layout_marginStart="8dp"
+        app:layout_constraintTop_toTopOf="@id/icon"
+        app:layout_constraintBottom_toBottomOf="@id/icon"
         app:layout_constraintStart_toEndOf="@id/icon"
-        app:layout_constraintEnd_toStartOf="@id/center_vertical_guideline"
+        app:layout_constraintEnd_toStartOf="@id/media_seamless"
+        app:layout_constraintHorizontal_chainStyle="spread_inside"
+        app:layout_constrainedWidth="true"
         app:layout_constraintHorizontal_bias="0"
         />
 
     <Constraint
         android:id="@+id/media_seamless"
-        android:layout_width="wrap_content"
+        android:layout_width="0dp"
         android:layout_height="wrap_content"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintTop_toTopOf="parent"
-        app:layout_constrainedWidth="true"
-        app:layout_constraintWidth_min="60dp"
-        app:layout_constraintStart_toEndOf="@id/center_vertical_guideline"
+        app:layout_constraintStart_toEndOf="@id/app_name"
+        app:layout_constraintHorizontal_chainStyle="spread_inside"
         app:layout_constraintHorizontal_bias="1"
-        android:layout_marginTop="@dimen/qs_media_panel_outer_padding"
-        android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
+        app:layout_constrainedWidth="true"
+        app:layout_constraintWidth_min="48dp"
+        app:layout_constraintHeight_min="48dp"
+        android:layout_marginEnd="@dimen/qs_center_guideline_padding"
         android:layout_marginStart="@dimen/qs_center_guideline_padding"
         />
 
@@ -64,22 +67,23 @@
         android:alpha="0.5"
         android:visibility="gone"
         app:layout_constraintHorizontal_bias="1"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toTopOf="@id/app_name"
-        app:layout_constraintBottom_toBottomOf="@id/app_name"
+        app:layout_constraintTop_toTopOf="@id/icon"
+        app:layout_constraintBottom_toBottomOf="@id/icon"
         app:layout_constraintStart_toEndOf="@id/center_vertical_guideline"
+        app:layout_constraintEnd_toEndOf="parent"
         />
 
     <Constraint
         android:id="@+id/album_art"
         android:layout_width="@dimen/qs_media_album_size"
         android:layout_height="@dimen/qs_media_album_size"
-        android:layout_marginTop="16dp"
+        android:layout_marginTop="@dimen/qs_media_panel_outer_padding"
         android:layout_marginStart="@dimen/qs_media_panel_outer_padding"
-        android:layout_marginBottom="24dp"
-        app:layout_constraintTop_toBottomOf="@id/icon"
+        android:layout_marginBottom="@dimen/qs_media_panel_outer_padding"
+        app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toStartOf="@id/media_action_barrier"
+        app:layout_constraintHorizontal_bias="0"
         />
 
     <!-- Song name -->
@@ -87,13 +91,14 @@
         android:id="@+id/header_title"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginTop="17dp"
-        android:layout_marginStart="16dp"
+        android:layout_marginTop="@dimen/qqs_media_spacing"
+        android:layout_marginStart="@dimen/qqs_media_spacing"
+        android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
         app:layout_constrainedWidth="true"
-        app:layout_constraintTop_toBottomOf="@id/app_name"
+        app:layout_constraintTop_toBottomOf="@id/icon"
         app:layout_constraintBottom_toTopOf="@id/header_artist"
         app:layout_constraintStart_toEndOf="@id/album_art"
-        app:layout_constraintEnd_toStartOf="@id/media_action_barrier"
+        app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintHorizontal_bias="0"/>
 
     <!-- Artist name -->
@@ -102,12 +107,12 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginTop="3dp"
-        android:layout_marginBottom="24dp"
+        android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
+        android:layout_marginBottom="@dimen/qqs_media_spacing"
         app:layout_constrainedWidth="true"
         app:layout_constraintTop_toBottomOf="@id/header_title"
         app:layout_constraintStart_toStartOf="@id/header_title"
-        app:layout_constraintEnd_toStartOf="@id/media_action_barrier"
-        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintHorizontal_bias="0"/>
 
     <!-- Seek Bar -->
@@ -140,15 +145,15 @@
         android:id="@+id/action0"
         android:layout_width="48dp"
         android:layout_height="48dp"
-        android:layout_marginStart="4dp"
+        android:layout_marginStart="@dimen/qqs_media_spacing"
         android:layout_marginEnd="4dp"
-        android:layout_marginTop="18dp"
+        android:layout_marginBottom="@dimen/qs_media_panel_outer_padding"
         android:visibility="gone"
         app:layout_constraintHorizontal_chainStyle="packed"
-        app:layout_constraintTop_toBottomOf="@id/app_name"
+        app:layout_constraintTop_toBottomOf="@id/header_artist"
         app:layout_constraintLeft_toLeftOf="parent"
         app:layout_constraintRight_toLeftOf="@id/action1"
-        app:layout_constraintHorizontal_bias="1"
+        app:layout_constraintHorizontal_bias="0"
         >
     </Constraint>
 
@@ -158,8 +163,9 @@
         android:layout_height="48dp"
         android:layout_marginStart="4dp"
         android:layout_marginEnd="4dp"
-        android:layout_marginTop="18dp"
-        app:layout_constraintTop_toBottomOf="@id/app_name"
+        android:layout_marginBottom="@dimen/qs_media_panel_outer_padding"
+        app:layout_constraintTop_toBottomOf="@id/header_artist"
+        app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintLeft_toRightOf="@id/action0"
         app:layout_constraintRight_toLeftOf="@id/action2"
         >
@@ -171,8 +177,9 @@
         android:layout_height="48dp"
         android:layout_marginStart="4dp"
         android:layout_marginEnd="4dp"
-        android:layout_marginTop="18dp"
-        app:layout_constraintTop_toBottomOf="@id/app_name"
+        android:layout_marginBottom="@dimen/qs_media_panel_outer_padding"
+        app:layout_constraintTop_toBottomOf="@id/header_artist"
+        app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintLeft_toRightOf="@id/action1"
         app:layout_constraintRight_toLeftOf="@id/action3"
         >
@@ -184,8 +191,9 @@
         android:layout_height="48dp"
         android:layout_marginStart="4dp"
         android:layout_marginEnd="4dp"
-        android:layout_marginTop="18dp"
-        app:layout_constraintTop_toBottomOf="@id/app_name"
+        android:layout_marginBottom="@dimen/qs_media_panel_outer_padding"
+        app:layout_constraintTop_toBottomOf="@id/header_artist"
+        app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintLeft_toRightOf="@id/action2"
         app:layout_constraintRight_toLeftOf="@id/action4"
         >
@@ -196,11 +204,12 @@
         android:layout_width="48dp"
         android:layout_height="48dp"
         android:layout_marginStart="4dp"
-        android:layout_marginEnd="4dp"
+        android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
         android:visibility="gone"
-        android:layout_marginTop="18dp"
+        android:layout_marginBottom="@dimen/qs_media_panel_outer_padding"
         app:layout_constraintHorizontal_chainStyle="packed"
-        app:layout_constraintTop_toBottomOf="@id/app_name"
+        app:layout_constraintTop_toBottomOf="@id/header_artist"
+        app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintLeft_toRightOf="@id/action3"
         app:layout_constraintRight_toRightOf="parent"
         app:layout_constraintHorizontal_bias="0"
diff --git a/packages/SystemUI/res/xml/media_expanded.xml b/packages/SystemUI/res/xml/media_expanded.xml
index d5a02c2..d89e0eb 100644
--- a/packages/SystemUI/res/xml/media_expanded.xml
+++ b/packages/SystemUI/res/xml/media_expanded.xml
@@ -22,36 +22,39 @@
         android:layout_width="@dimen/qs_media_icon_size"
         android:layout_height="@dimen/qs_media_icon_size"
         android:layout_marginStart="18dp"
-        app:layout_constraintTop_toTopOf="@id/app_name"
-        app:layout_constraintBottom_toBottomOf="@id/app_name"
-        app:layout_constraintStart_toStartOf="parent"
+        android:layout_marginTop="@dimen/qs_media_panel_outer_padding"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintStart_toEndOf="@id/album_art"
         />
 
     <Constraint
         android:id="@+id/app_name"
-        android:layout_width="0dp"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginEnd="@dimen/qs_center_guideline_padding"
-        android:layout_marginStart="10dp"
-        android:layout_marginTop="20dp"
-        app:layout_constraintTop_toTopOf="parent"
+        android:layout_marginStart="8dp"
+        app:layout_constraintTop_toTopOf="@id/icon"
+        app:layout_constraintBottom_toBottomOf="@id/icon"
         app:layout_constraintStart_toEndOf="@id/icon"
-        app:layout_constraintEnd_toStartOf="@id/center_vertical_guideline"
+        app:layout_constraintEnd_toStartOf="@id/media_seamless"
+        app:layout_constraintHorizontal_chainStyle="spread_inside"
+        app:layout_constrainedWidth="true"
         app:layout_constraintHorizontal_bias="0"
         />
 
     <Constraint
         android:id="@+id/media_seamless"
-        android:layout_width="wrap_content"
+        android:layout_width="0dp"
         android:layout_height="wrap_content"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintStart_toEndOf="@id/center_vertical_guideline"
+        app:layout_constraintStart_toEndOf="@id/app_name"
+        app:layout_constraintHorizontal_chainStyle="spread_inside"
         app:layout_constraintHorizontal_bias="1"
         app:layout_constrainedWidth="true"
-        app:layout_constraintWidth_min="60dp"
-        android:layout_marginTop="@dimen/qs_media_panel_outer_padding"
-        android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
+        app:layout_constraintWidth_min="48dp"
+        app:layout_constraintHeight_min="48dp"
+        android:layout_marginEnd="@dimen/qs_center_guideline_padding"
         android:layout_marginStart="@dimen/qs_center_guideline_padding"
         />
 
@@ -63,20 +66,21 @@
         android:layout_marginStart="@dimen/qs_center_guideline_padding"
         android:alpha="0.5"
         android:visibility="gone"
-        app:layout_constraintTop_toTopOf="@id/app_name"
-        app:layout_constraintBottom_toBottomOf="@id/app_name"
+        app:layout_constraintHorizontal_bias="1"
+        app:layout_constraintTop_toTopOf="@id/icon"
+        app:layout_constraintBottom_toBottomOf="@id/icon"
         app:layout_constraintStart_toEndOf="@id/center_vertical_guideline"
         app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintHorizontal_bias="1"
         />
 
     <Constraint
         android:id="@+id/album_art"
         android:layout_width="@dimen/qs_media_album_size"
         android:layout_height="@dimen/qs_media_album_size"
-        android:layout_marginTop="14dp"
+        android:layout_marginTop="@dimen/qs_media_panel_outer_padding"
         android:layout_marginStart="@dimen/qs_media_panel_outer_padding"
-        app:layout_constraintTop_toBottomOf="@+id/app_name"
+        android:layout_marginBottom="@dimen/qqs_media_spacing"
+        app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintStart_toStartOf="parent"
         />
 
@@ -85,11 +89,11 @@
         android:id="@+id/header_title"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/qqs_media_spacing"
+        android:layout_marginStart="@dimen/qqs_media_spacing"
         android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
-        android:layout_marginTop="17dp"
-        android:layout_marginStart="16dp"
         app:layout_constrainedWidth="true"
-        app:layout_constraintTop_toBottomOf="@+id/app_name"
+        app:layout_constraintTop_toBottomOf="@+id/icon"
         app:layout_constraintStart_toEndOf="@id/album_art"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintHorizontal_bias="0"/>
@@ -100,6 +104,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
+        android:layout_marginBottom="@dimen/qqs_media_spacing"
         android:layout_marginTop="3dp"
         app:layout_constrainedWidth="true"
         app:layout_constraintTop_toBottomOf="@id/header_title"
@@ -112,7 +117,7 @@
         android:id="@+id/media_progress_bar"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
-        android:layout_marginTop="3dp"
+        android:layout_marginTop="35dp"
         app:layout_constraintTop_toBottomOf="@id/header_artist"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
@@ -122,7 +127,7 @@
         android:id="@+id/notification_media_progress_time"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
-        android:layout_marginTop="38dp"
+        android:layout_marginTop="70dp"
         android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
         android:layout_marginStart="@dimen/qs_media_panel_outer_padding"
         app:layout_constraintTop_toBottomOf="@id/header_artist"
@@ -135,13 +140,12 @@
         android:layout_width="48dp"
         android:layout_height="48dp"
         android:layout_marginTop="5dp"
-        android:layout_marginStart="4dp"
-        android:layout_marginEnd="4dp"
+        android:layout_marginStart="@dimen/qs_media_panel_outer_padding"
         android:layout_marginBottom="@dimen/qs_media_panel_outer_padding"
         app:layout_constraintHorizontal_chainStyle="packed"
         app:layout_constraintLeft_toLeftOf="parent"
         app:layout_constraintRight_toLeftOf="@id/action1"
-        app:layout_constraintTop_toBottomOf="@id/notification_media_progress_time"
+        app:layout_constraintTop_toBottomOf="@id/media_progress_bar"
         app:layout_constraintBottom_toBottomOf="parent">
     </Constraint>
 
@@ -155,6 +159,7 @@
         app:layout_constraintLeft_toRightOf="@id/action0"
         app:layout_constraintRight_toLeftOf="@id/action2"
         app:layout_constraintTop_toTopOf="@id/action0"
+        app:layout_constraintTop_toBottomOf="@id/media_progress_bar"
         app:layout_constraintBottom_toBottomOf="parent">
     </Constraint>
 
@@ -167,7 +172,7 @@
         android:layout_marginBottom="@dimen/qs_media_panel_outer_padding"
         app:layout_constraintLeft_toRightOf="@id/action1"
         app:layout_constraintRight_toLeftOf="@id/action3"
-        app:layout_constraintTop_toTopOf="@id/action0"
+        app:layout_constraintTop_toBottomOf="@id/media_progress_bar"
         app:layout_constraintBottom_toBottomOf="parent">
     </Constraint>
 
@@ -177,10 +182,10 @@
         android:layout_height="48dp"
         android:layout_marginStart="4dp"
         android:layout_marginEnd="4dp"
+        android:layout_marginBottom="@dimen/qs_media_panel_outer_padding"
         app:layout_constraintLeft_toRightOf="@id/action2"
         app:layout_constraintRight_toLeftOf="@id/action4"
-        app:layout_constraintTop_toTopOf="@id/action0"
-        android:layout_marginBottom="@dimen/qs_media_panel_outer_padding"
+        app:layout_constraintTop_toBottomOf="@id/media_progress_bar"
         app:layout_constraintBottom_toBottomOf="parent">
     </Constraint>
 
@@ -189,12 +194,12 @@
         android:layout_width="48dp"
         android:layout_height="48dp"
         android:layout_marginStart="4dp"
-        android:layout_marginEnd="4dp"
+        android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
         android:layout_marginBottom="@dimen/qs_media_panel_outer_padding"
         app:layout_constraintHorizontal_chainStyle="packed"
         app:layout_constraintLeft_toRightOf="@id/action3"
         app:layout_constraintRight_toRightOf="parent"
-        app:layout_constraintTop_toTopOf="@id/action0"
+        app:layout_constraintTop_toBottomOf="@id/media_progress_bar"
         app:layout_constraintBottom_toBottomOf="parent">
     </Constraint>
 </ConstraintSet>
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index 6eec5dc..902de23 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -50,6 +50,10 @@
             android:key="bluetooth"
             android:title="@string/quick_settings_bluetooth_label" />
 
+        <com.android.systemui.tuner.StatusBarSwitch
+            android:key="cameratoggle"
+            android:title="@string/quick_settings_camera_label" />
+
         <!-- nfc -->
         <!-- tty -->
         <!-- speakerphone -->
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 e4427f4..57a4dab 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
@@ -24,9 +24,11 @@
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.view.MotionEvent;
+import android.window.TransitionFilter;
 
 import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
 import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.system.RemoteTransitionCompat;
 
 /**
  * Temporary callbacks into SystemUI.
@@ -192,4 +194,13 @@
      * @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;
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
index d672c2c..325e268 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
@@ -60,7 +60,8 @@
 
     public static ActivityOptions makeRemoteAnimation(
             RemoteAnimationAdapterCompat remoteAnimationAdapter) {
-        return ActivityOptions.makeRemoteAnimation(remoteAnimationAdapter.getWrapped());
+        return ActivityOptions.makeRemoteAnimation(remoteAnimationAdapter.getWrapped(),
+                remoteAnimationAdapter.getRemoteTransition().getTransition());
     }
 
     public static ActivityOptions makeCustomAnimation(Context context, int enterResId,
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 02e509e..f105fce 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
@@ -16,12 +16,21 @@
 
 package com.android.systemui.shared.system;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.view.WindowManager.TRANSIT_CLOSE;
+import static android.view.WindowManager.TRANSIT_OPEN;
+import static android.view.WindowManager.TRANSIT_TO_BACK;
+import static android.view.WindowManager.TRANSIT_TO_FRONT;
+
 import android.os.RemoteException;
 import android.util.Log;
 import android.view.IRemoteAnimationFinishedCallback;
 import android.view.IRemoteAnimationRunner;
 import android.view.RemoteAnimationAdapter;
 import android.view.RemoteAnimationTarget;
+import android.view.SurfaceControl;
+import android.window.IRemoteTransition;
+import android.window.TransitionInfo;
 
 /**
  * @see RemoteAnimationAdapter
@@ -29,17 +38,28 @@
 public class RemoteAnimationAdapterCompat {
 
     private final RemoteAnimationAdapter mWrapped;
+    private final RemoteTransitionCompat mRemoteTransition;
 
     public RemoteAnimationAdapterCompat(RemoteAnimationRunnerCompat runner, long duration,
             long statusBarTransitionDelay) {
         mWrapped = new RemoteAnimationAdapter(wrapRemoteAnimationRunner(runner), duration,
                 statusBarTransitionDelay);
+        mRemoteTransition = buildRemoteTransition(runner);
     }
 
     RemoteAnimationAdapter getWrapped() {
         return mWrapped;
     }
 
+    /** Helper to just build a remote transition. Use this if the legacy adapter isn't needed. */
+    public static RemoteTransitionCompat buildRemoteTransition(RemoteAnimationRunnerCompat runner) {
+        return new RemoteTransitionCompat(wrapRemoteTransition(runner));
+    }
+
+    public RemoteTransitionCompat getRemoteTransition() {
+        return mRemoteTransition;
+    }
+
     private static IRemoteAnimationRunner.Stub wrapRemoteAnimationRunner(
             final RemoteAnimationRunnerCompat remoteAnimationAdapter) {
         return new IRemoteAnimationRunner.Stub() {
@@ -72,4 +92,63 @@
             }
         };
     }
+
+    private static IRemoteTransition.Stub wrapRemoteTransition(
+            final RemoteAnimationRunnerCompat remoteAnimationAdapter) {
+        return new IRemoteTransition.Stub() {
+            @Override
+            public void startAnimation(TransitionInfo info, SurfaceControl.Transaction t,
+                    IRemoteAnimationFinishedCallback finishCallback) {
+                final RemoteAnimationTargetCompat[] appsCompat =
+                        RemoteAnimationTargetCompat.wrap(info, false /* wallpapers */);
+                final RemoteAnimationTargetCompat[] wallpapersCompat =
+                        RemoteAnimationTargetCompat.wrap(info, true /* wallpapers */);
+                final Runnable animationFinishedCallback = new Runnable() {
+                    @Override
+                    public void run() {
+                        try {
+                            finishCallback.onAnimationFinished();
+                        } catch (RemoteException e) {
+                            Log.e("ActivityOptionsCompat", "Failed to call app controlled animation"
+                                    + " finished callback", e);
+                        }
+                    }
+                };
+
+                // TODO(b/177438007): Move this set-up logic into launcher's animation impl.
+                boolean isReturnToHome = false;
+                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;
+                    }
+                }
+
+                if (isReturnToHome) {
+                    // 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);
+                        final SurfaceControl leash = change.getLeash();
+                        final int mode = info.getChanges().get(i).getMode();
+                        // Only deal with roots
+                        if (change.getParent() != null) continue;
+                        if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) {
+                            t.setLayer(leash, info.getChanges().size() * 3 - i);
+                        }
+                    }
+                    // Make wallpaper visible immediately since launcher apparently won't do this.
+                    for (int i = wallpapersCompat.length - 1; i >= 0; --i) {
+                        t.show(wallpapersCompat[i].leash.getSurfaceControl());
+                        t.setAlpha(wallpapersCompat[i].leash.getSurfaceControl(), 1.f);
+                    }
+                }
+                t.apply();
+                remoteAnimationAdapter.onAnimationStart(appsCompat, wallpapersCompat,
+                        animationFinishedCallback);
+            }
+        };
+    }
 }
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 a1c1f93..f88e38a 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
@@ -22,6 +22,10 @@
 import android.graphics.Rect;
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
+import android.view.WindowManager;
+import android.window.TransitionInfo;
+
+import java.util.ArrayList;
 
 /**
  * @see RemoteAnimationTarget
@@ -73,6 +77,45 @@
         mStartLeash = app.startLeash;
     }
 
+    private static int newModeToLegacyMode(int newMode) {
+        switch (newMode) {
+            case WindowManager.TRANSIT_OPEN:
+            case WindowManager.TRANSIT_TO_FRONT:
+                return MODE_OPENING;
+            case WindowManager.TRANSIT_CLOSE:
+            case WindowManager.TRANSIT_TO_BACK:
+                return MODE_CLOSING;
+            default:
+                return 2; // MODE_CHANGING
+        }
+    }
+
+    public RemoteAnimationTargetCompat(TransitionInfo.Change change, int order) {
+        taskId = change.getTaskInfo() != null ? change.getTaskInfo().taskId : -1;
+        mode = newModeToLegacyMode(change.getMode());
+        leash = new SurfaceControlCompat(change.getLeash());
+        isTranslucent = (change.getFlags() & TransitionInfo.FLAG_TRANSLUCENT) != 0
+                || (change.getFlags() & TransitionInfo.FLAG_SHOW_WALLPAPER) != 0;
+        clipRect = null;
+        position = null;
+        localBounds = new Rect(change.getEndAbsBounds());
+        localBounds.offsetTo(change.getEndRelOffset().x, change.getEndRelOffset().y);
+        sourceContainerBounds = null;
+        screenSpaceBounds = 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);
+        if (change.getTaskInfo() != null) {
+            isNotInRecents = !change.getTaskInfo().isRunning;
+            activityType = change.getTaskInfo().getActivityType();
+        } else {
+            isNotInRecents = true;
+            activityType = ACTIVITY_TYPE_UNDEFINED;
+        }
+        pictureInPictureParams = null;
+        mStartLeash = null;
+    }
+
     public static RemoteAnimationTargetCompat[] wrap(RemoteAnimationTarget[] apps) {
         final RemoteAnimationTargetCompat[] appsCompat =
                 new RemoteAnimationTargetCompat[apps != null ? apps.length : 0];
@@ -83,6 +126,24 @@
     }
 
     /**
+     * Represents a TransitionInfo object as an array of old-style targets
+     *
+     * @param wallpapers If true, this will return wallpaper targets; otherwise it returns
+     *                   non-wallpaper targets.
+     */
+    public static RemoteAnimationTargetCompat[] wrap(TransitionInfo info, boolean wallpapers) {
+        final ArrayList<RemoteAnimationTargetCompat> out = new ArrayList<>();
+        for (int i = 0; i < info.getChanges().size(); i++) {
+            boolean changeIsWallpaper =
+                    (info.getChanges().get(i).getFlags() & TransitionInfo.FLAG_IS_WALLPAPER) != 0;
+            if (wallpapers != changeIsWallpaper) continue;
+            out.add(new RemoteAnimationTargetCompat(info.getChanges().get(i),
+                    info.getChanges().size() - i));
+        }
+        return out.toArray(new RemoteAnimationTargetCompat[out.size()]);
+    }
+
+    /**
      * @see SurfaceControl#release()
      */
     public void release() {
@@ -91,4 +152,4 @@
             mStartLeash.release();
         }
     }
-}
\ No newline at end of file
+}
diff --git a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.aidl
similarity index 64%
copy from media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl
copy to packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.aidl
index edf96dd..1550ab3 100644
--- a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.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.
@@ -14,17 +14,6 @@
  * limitations under the License.
  */
 
-package android.media.tv.tunerresourcemanager;
+package com.android.systemui.shared.system;
 
-/**
- * Simple container of the FrontendInfo struct defined in the TunerHAL 1.0 interface.
- *
- * @hide
- */
-parcelable TunerFrontendInfo {
-    int handle;
-
-    int frontendType;
-
-    int exclusiveGroupId;
-}
+parcelable RemoteTransitionCompat;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
new file mode 100644
index 0000000..5c27b89
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
@@ -0,0 +1,213 @@
+/*
+ * 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.shared.system;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.view.WindowManager.TRANSIT_OPEN;
+import static android.view.WindowManager.TRANSIT_TO_FRONT;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcelable;
+import android.window.IRemoteTransition;
+import android.window.TransitionFilter;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * Wrapper to expose RemoteTransition (shell transitions) to Launcher.
+ *
+ * @see IRemoteTransition
+ * @see TransitionFilter
+ */
+@DataClass
+public class RemoteTransitionCompat implements Parcelable {
+    @NonNull final IRemoteTransition mTransition;
+    @Nullable TransitionFilter mFilter = null;
+
+    RemoteTransitionCompat(IRemoteTransition transition) {
+        mTransition = transition;
+    }
+
+    /** Adds a filter check that restricts this remote transition to home open transitions. */
+    public void addHomeOpenCheck() {
+        if (mFilter == null) {
+            mFilter = new TransitionFilter();
+        }
+        mFilter.mRequirements =
+                new TransitionFilter.Requirement[]{new TransitionFilter.Requirement()};
+        mFilter.mRequirements[0].mActivityType = ACTIVITY_TYPE_HOME;
+        mFilter.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT};
+    }
+
+
+
+    // Code below generated by codegen v1.0.21.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.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 */ RemoteTransitionCompat(
+            @NonNull IRemoteTransition transition,
+            @Nullable TransitionFilter filter) {
+        this.mTransition = transition;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mTransition);
+        this.mFilter = filter;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull IRemoteTransition getTransition() {
+        return mTransition;
+    }
+
+    @DataClass.Generated.Member
+    public @Nullable TransitionFilter getFilter() {
+        return mFilter;
+    }
+
+    @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 (mFilter != null) flg |= 0x2;
+        dest.writeByte(flg);
+        dest.writeStrongInterface(mTransition);
+        if (mFilter != null) dest.writeTypedObject(mFilter, flags);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    protected RemoteTransitionCompat(@NonNull android.os.Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        byte flg = in.readByte();
+        IRemoteTransition transition = IRemoteTransition.Stub.asInterface(in.readStrongBinder());
+        TransitionFilter filter = (flg & 0x2) == 0 ? null : (TransitionFilter) in.readTypedObject(TransitionFilter.CREATOR);
+
+        this.mTransition = transition;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mTransition);
+        this.mFilter = filter;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<RemoteTransitionCompat> CREATOR
+            = new Parcelable.Creator<RemoteTransitionCompat>() {
+        @Override
+        public RemoteTransitionCompat[] newArray(int size) {
+            return new RemoteTransitionCompat[size];
+        }
+
+        @Override
+        public RemoteTransitionCompat createFromParcel(@NonNull android.os.Parcel in) {
+            return new RemoteTransitionCompat(in);
+        }
+    };
+
+    /**
+     * A builder for {@link RemoteTransitionCompat}
+     */
+    @SuppressWarnings("WeakerAccess")
+    @DataClass.Generated.Member
+    public static class Builder {
+
+        private @NonNull IRemoteTransition mTransition;
+        private @Nullable TransitionFilter mFilter;
+
+        private long mBuilderFieldsSet = 0L;
+
+        public Builder(
+                @NonNull IRemoteTransition transition) {
+            mTransition = transition;
+            com.android.internal.util.AnnotationValidations.validate(
+                    NonNull.class, null, mTransition);
+        }
+
+        @DataClass.Generated.Member
+        public @NonNull Builder setTransition(@NonNull IRemoteTransition value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x1;
+            mTransition = value;
+            return this;
+        }
+
+        @DataClass.Generated.Member
+        public @NonNull Builder setFilter(@NonNull TransitionFilter value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x2;
+            mFilter = value;
+            return this;
+        }
+
+        /** Builds the instance. This builder should not be touched after calling this! */
+        public @NonNull RemoteTransitionCompat build() {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x4; // Mark builder used
+
+            if ((mBuilderFieldsSet & 0x2) == 0) {
+                mFilter = null;
+            }
+            RemoteTransitionCompat o = new RemoteTransitionCompat(
+                    mTransition,
+                    mFilter);
+            return o;
+        }
+
+        private void checkNotUsed() {
+            if ((mBuilderFieldsSet & 0x4) != 0) {
+                throw new IllegalStateException(
+                        "This Builder should not be reused. Use a new Builder instance instead");
+            }
+        }
+    }
+
+    @DataClass.Generated(
+            time = 1606862689344L,
+            codegenVersion = "1.0.21",
+            sourceFile = "frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java",
+            inputSignatures = "final @android.annotation.NonNull com.android.systemui.shared.system.IRemoteTransition mTransition\n @android.annotation.Nullable android.window.TransitionFilter mFilter\npublic  void addHomeOpenCheck()\nclass RemoteTransitionCompat extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index deca14a..19520df 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -30,6 +30,7 @@
 import com.android.systemui.dagger.WMComponent;
 import com.android.systemui.navigationbar.gestural.BackGestureTfClassifierProvider;
 import com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider;
+import com.android.wm.shell.transition.Transitions;
 
 import java.util.Optional;
 import java.util.concurrent.ExecutionException;
@@ -113,7 +114,8 @@
                     .setHideDisplayCutout(mWMComponent.getHideDisplayCutout())
                     .setShellCommandHandler(mWMComponent.getShellCommandHandler())
                     .setAppPairs(mWMComponent.getAppPairs())
-                    .setTaskViewFactory(mWMComponent.getTaskViewFactory());
+                    .setTaskViewFactory(mWMComponent.getTaskViewFactory())
+                    .setTransitions(mWMComponent.getTransitions());
         } else {
             // TODO: Call on prepareSysUIComponentBuilder but not with real components. Other option
             // is separating this logic into newly creating SystemUITestsFactory.
@@ -126,7 +128,8 @@
                     .setHideDisplayCutout(Optional.ofNullable(null))
                     .setShellCommandHandler(Optional.ofNullable(null))
                     .setAppPairs(Optional.ofNullable(null))
-                    .setTaskViewFactory(Optional.ofNullable(null));
+                    .setTaskViewFactory(Optional.ofNullable(null))
+                    .setTransitions(Transitions.createEmptyForTesting());
         }
         mSysUIComponent = builder.build();
         if (initializeComponents) {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
index e6ad1cb..13da2b0 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
@@ -16,7 +16,7 @@
 
 package com.android.systemui.accessibility;
 
-import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_GLOBAL_ACTIONS;
+import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_ACCESSIBILITY_ACTIONS;
 
 import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
 
@@ -349,7 +349,7 @@
     private void handleTakeScreenshot() {
         ScreenshotHelper screenshotHelper = new ScreenshotHelper(mContext);
         screenshotHelper.takeScreenshot(WindowManager.TAKE_SCREENSHOT_FULLSCREEN, true, true,
-                SCREENSHOT_GLOBAL_ACTIONS, new Handler(Looper.getMainLooper()), null);
+                SCREENSHOT_ACCESSIBILITY_ACTIONS, new Handler(Looper.getMainLooper()), null);
     }
 
     private void handleAccessibilityButton() {
diff --git a/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java b/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
index 61951cc..169a9c0 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
@@ -112,7 +112,7 @@
         } else if (mLauncherShowing) {
             phoneState = getPhoneLauncherState();
         } else {
-            phoneState = getPhoneAppState();
+            phoneState = PHONE_STATE_APP_IMMERSIVE;
         }
         return phoneState;
     }
@@ -161,16 +161,6 @@
         }
     }
 
-    private int getPhoneAppState() {
-        if (isAppImmersive()) {
-            return PHONE_STATE_APP_IMMERSIVE;
-        } else if (isAppFullscreen()) {
-            return PHONE_STATE_APP_FULLSCREEN;
-        } else {
-            return PHONE_STATE_APP_DEFAULT;
-        }
-    }
-
     private boolean isShadeFullscreen() {
         int statusBarState = mStatusBarStateController.getState();
         return statusBarState == StatusBarState.KEYGUARD
@@ -189,14 +179,6 @@
         }
     }
 
-    private boolean isAppImmersive() {
-        return mStatusBarOptionalLazy.get().get().inImmersiveMode();
-    }
-
-    private boolean isAppFullscreen() {
-        return mStatusBarOptionalLazy.get().get().inFullscreenMode();
-    }
-
     private boolean isBouncerShowing() {
         return mStatusBarOptionalLazy.map(
                 statusBarLazy -> statusBarLazy.get().isBouncerShowing()).orElse(false);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java
index e4f6d6c..9b09cfd 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java
@@ -160,12 +160,12 @@
 
     @Override
     protected void handleResetAfterError() {
-        resetErrorView(mContext, mIndicatorView);
+        resetErrorView();
     }
 
     @Override
     protected void handleResetAfterHelp() {
-        resetErrorView(mContext, mIndicatorView);
+        resetErrorView();
     }
 
     @Override
@@ -185,7 +185,7 @@
 
         if (newState == STATE_AUTHENTICATING_ANIMATING_IN ||
                 (newState == STATE_AUTHENTICATING && getSize() == AuthDialog.SIZE_MEDIUM)) {
-            resetErrorView(mContext, mIndicatorView);
+            resetErrorView();
         }
 
         // Do this last since the state variable gets updated.
@@ -204,9 +204,8 @@
         super.onAuthenticationFailed(failureReason);
     }
 
-    static void resetErrorView(Context context, TextView textView) {
-        textView.setTextColor(context.getResources().getColor(
-                R.color.biometric_dialog_gray, context.getTheme()));
-        textView.setVisibility(View.INVISIBLE);
+    private void resetErrorView() {
+        mIndicatorView.setTextColor(mTextColorHint);
+        mIndicatorView.setVisibility(View.INVISIBLE);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.java
index 176e9e6..45ee4ad 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.java
@@ -78,7 +78,7 @@
 
     private void showTouchSensorString() {
         mIndicatorView.setText(R.string.fingerprint_dialog_touch_sensor);
-        mIndicatorView.setTextColor(R.color.biometric_dialog_gray);
+        mIndicatorView.setTextColor(mTextColorHint);
     }
 
     private void updateIcon(int lastState, int newState) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
index c748ab2..18206ef 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
@@ -83,7 +83,7 @@
      * Authenticated, dialog animating away soon.
      */
     protected static final int STATE_AUTHENTICATED = 6;
-    
+
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({STATE_IDLE, STATE_AUTHENTICATING_ANIMATING_IN, STATE_AUTHENTICATING, STATE_HELP,
             STATE_ERROR, STATE_PENDING_CONFIRMATION, STATE_AUTHENTICATED})
@@ -168,8 +168,8 @@
     private final Injector mInjector;
     private final Handler mHandler;
     private final AccessibilityManager mAccessibilityManager;
-    private final int mTextColorError;
-    private final int mTextColorHint;
+    protected final int mTextColorError;
+    protected final int mTextColorHint;
 
     private AuthPanelController mPanelController;
     private PromptInfo mPromptInfo;
@@ -183,7 +183,7 @@
     private TextView mDescriptionView;
     private View mIconHolderView;
     protected ImageView mIconView;
-    @VisibleForTesting protected TextView mIndicatorView;
+    protected TextView mIndicatorView;
 
     // Negative button position, exclusively for the app-specified behavior
     @VisibleForTesting Button mNegativeButton;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index dcb6ea3..1cafb4c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -342,8 +342,8 @@
                     Log.v(TAG, "showUdfpsOverlay | adding window");
                     mView.setShowReason(reason);
                     mWindowManager.addView(mView, computeLayoutParams());
-                    mIsOverlayShowing = true;
                     mView.setOnTouchListener(mOnTouchListener);
+                    mIsOverlayShowing = true;
                 } catch (RuntimeException e) {
                     Log.e(TAG, "showUdfpsOverlay | failed to add window", e);
                 }
@@ -434,19 +434,21 @@
     }
 
     private void onFingerDown(int x, int y, float minor, float major) {
-        mView.setScrimAlpha(computeScrimOpacity());
-        mView.showScrimAndDot();
-        try {
-            if (mHbmSupported) {
+        if (mHbmSupported) {
+            try {
                 FileWriter fw = new FileWriter(mHbmPath);
                 fw.write(mHbmEnableCommand);
                 fw.close();
+            } catch (IOException e) {
+                mView.hideScrimAndDot();
+                Log.e(TAG, "onFingerDown | failed to enable HBM: " + e.getMessage());
             }
-            mFingerprintManager.onPointerDown(mSensorProps.sensorId, x, y, minor, major);
-        } catch (IOException e) {
-            mView.hideScrimAndDot();
-            Log.e(TAG, "onFingerDown | failed to enable HBM: " + e.getMessage());
         }
+        mView.setScrimAlpha(computeScrimOpacity());
+        mView.setRunAfterShowingScrimAndDot(() -> {
+            mFingerprintManager.onPointerDown(mSensorProps.sensorId, x, y, minor, major);
+        });
+        mView.showScrimAndDot();
     }
 
     private void onFingerUp() {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
index a42ab58..c2f80d4 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
@@ -89,6 +89,10 @@
     private boolean mIsHbmSupported;
     @Nullable private String mDebugMessage;
 
+    // Runnable that will be run after the illumination dot and scrim are shown.
+    // The runnable is reset to null after it's executed once.
+    @Nullable private Runnable mRunAfterShowingScrimAndDot;
+
     public UdfpsView(Context context, AttributeSet attrs) {
         super(context, attrs);
 
@@ -279,6 +283,11 @@
         }
 
         canvas.restore();
+
+        if (mShowScrimAndDot && mRunAfterShowingScrimAndDot != null) {
+            post(mRunAfterShowingScrimAndDot);
+            mRunAfterShowingScrimAndDot = null;
+        }
     }
 
     RectF getSensorRect() {
@@ -294,6 +303,10 @@
         postInvalidate();
     }
 
+    void setRunAfterShowingScrimAndDot(Runnable runnable) {
+        mRunAfterShowingScrimAndDot = runnable;
+    }
+
     boolean isValidTouch(float x, float y, float pressure) {
         // The X and Y coordinates of the sensor's center.
         final float cx = mSensorRect.centerX();
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index 82d313e..062410a 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -33,6 +33,7 @@
 import com.android.wm.shell.onehanded.OneHanded;
 import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.splitscreen.SplitScreen;
+import com.android.wm.shell.transition.Transitions;
 
 import java.util.Optional;
 
@@ -84,6 +85,9 @@
         @BindsInstance
         Builder setShellCommandHandler(Optional<ShellCommandHandler> shellDump);
 
+        @BindsInstance
+        Builder setTransitions(Transitions t);
+
         SysUIComponent build();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
index 7ca8e63..239a77e 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
@@ -20,6 +20,7 @@
 import static com.android.systemui.Dependency.LEAK_REPORT_EMAIL_NAME;
 
 import android.content.Context;
+import android.hardware.SensorPrivacyManager;
 import android.os.Handler;
 import android.os.PowerManager;
 
@@ -62,6 +63,10 @@
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
+import com.android.systemui.statusbar.policy.IndividualSensorPrivacyControllerImpl;
+import com.android.systemui.statusbar.policy.SensorPrivacyController;
+import com.android.systemui.statusbar.policy.SensorPrivacyControllerImpl;
 
 import javax.inject.Named;
 
@@ -116,6 +121,25 @@
         return bC;
     }
 
+    @Provides
+    @SysUISingleton
+    static SensorPrivacyController provideSensorPrivacyController(
+            SensorPrivacyManager sensorPrivacyManager) {
+        SensorPrivacyController spC = new SensorPrivacyControllerImpl(sensorPrivacyManager);
+        spC.init();
+        return spC;
+    }
+
+    @Provides
+    @SysUISingleton
+    static IndividualSensorPrivacyController provideIndividualSensorPrivacyController(
+            SensorPrivacyManager sensorPrivacyManager) {
+        IndividualSensorPrivacyController spC = new IndividualSensorPrivacyControllerImpl(
+                sensorPrivacyManager);
+        spC.init();
+        return spC;
+    }
+
     @Binds
     @SysUISingleton
     public abstract QSFactory bindQSFactory(QSFactoryImpl qsFactoryImpl);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index ced606c..60b665f 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -27,6 +27,7 @@
 import com.android.wm.shell.onehanded.OneHanded;
 import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.splitscreen.SplitScreen;
+import com.android.wm.shell.transition.Transitions;
 
 import java.util.Optional;
 
@@ -87,4 +88,8 @@
 
     @WMSingleton
     Optional<TaskViewFactory> getTaskViewFactory();
+
+    /** Gets transitions */
+    @WMSingleton
+    Transitions getTransitions();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index c18a6a4..743ac86 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -29,6 +29,7 @@
 import android.media.session.MediaController;
 import android.media.session.MediaSession;
 import android.media.session.PlaybackState;
+import android.os.SystemProperties;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewOutlineProvider;
@@ -64,6 +65,11 @@
     private static final String TAG = "MediaControlPanel";
     private static final float DISABLED_ALPHA = 0.38f;
 
+    private final boolean mShowAppName = SystemProperties.getBoolean(
+            "persist.sysui.qs_media_show_app_name", false);
+    private final boolean mShowDeviceName = SystemProperties.getBoolean(
+            "persist.sysui.qs_media_show_device_name", false);
+
     private static final Intent SETTINGS_INTENT = new Intent(ACTION_MEDIA_CONTROLS_SETTINGS);
 
     // Button IDs for QS controls
@@ -265,6 +271,9 @@
         // App title
         TextView appName = mViewHolder.getAppName();
         appName.setText(data.getApp());
+        appName.setVisibility(mShowAppName ? View.VISIBLE : View.GONE);
+        setVisibleAndAlpha(collapsedSet, R.id.app_name, mShowAppName);
+        setVisibleAndAlpha(expandedSet, R.id.app_name, mShowAppName);
 
         // Artist name
         TextView artistText = mViewHolder.getArtistText();
@@ -277,6 +286,10 @@
         mViewHolder.getSeamless().setOnClickListener(v -> {
             mMediaOutputDialogFactory.create(data.getPackageName(), true);
         });
+        TextView mDeviceName = mViewHolder.getSeamlessText();
+        mDeviceName.setVisibility(mShowDeviceName ? View.VISIBLE : View.GONE);
+        setVisibleAndAlpha(collapsedSet, R.id.media_seamless_text, mShowDeviceName);
+        setVisibleAndAlpha(expandedSet, R.id.media_seamless_text, mShowDeviceName);
 
         ImageView iconView = mViewHolder.getSeamlessIcon();
         TextView deviceName = mViewHolder.getSeamlessText();
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index a23b07c..34d1f6e 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -28,6 +28,7 @@
 import static android.view.InsetsState.containsType;
 import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
 import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS;
+import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
@@ -37,6 +38,7 @@
 import static com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
@@ -91,6 +93,7 @@
 import android.view.View;
 import android.view.ViewTreeObserver;
 import android.view.WindowInsetsController.Appearance;
+import android.view.WindowInsetsController.Behavior;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
@@ -159,6 +162,7 @@
     private static final String EXTRA_DISABLE_STATE = "disabled_state";
     private static final String EXTRA_DISABLE2_STATE = "disabled2_state";
     private static final String EXTRA_APPEARANCE = "appearance";
+    private static final String EXTRA_BEHAVIOR = "behavior";
     private static final String EXTRA_TRANSIENT_STATE = "transient_state";
 
     /** Allow some time inbetween the long press for back and recents. */
@@ -209,9 +213,12 @@
     private boolean mForceNavBarHandleOpaque;
     private boolean mIsCurrentUserSetup;
 
-    /** @see android.view.WindowInsetsController#setSystemBarsAppearance(int) */
+    /** @see android.view.WindowInsetsController#setSystemBarsAppearance(int, int) */
     private @Appearance int mAppearance;
 
+    /** @see android.view.WindowInsetsController#setSystemBarsBehavior(int) */
+    private @Behavior int mBehavior;
+
     private boolean mTransientShown;
     private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
     private LightBarController mLightBarController;
@@ -489,6 +496,7 @@
             mDisabledFlags1 = savedState.getInt(EXTRA_DISABLE_STATE, 0);
             mDisabledFlags2 = savedState.getInt(EXTRA_DISABLE2_STATE, 0);
             mAppearance = savedState.getInt(EXTRA_APPEARANCE, 0);
+            mBehavior = savedState.getInt(EXTRA_BEHAVIOR, 0);
             mTransientShown = savedState.getBoolean(EXTRA_TRANSIENT_STATE, false);
         }
         mSavedState = savedState;
@@ -629,6 +637,7 @@
         outState.putInt(EXTRA_DISABLE_STATE, mDisabledFlags1);
         outState.putInt(EXTRA_DISABLE2_STATE, mDisabledFlags2);
         outState.putInt(EXTRA_APPEARANCE, mAppearance);
+        outState.putInt(EXTRA_BEHAVIOR, mBehavior);
         outState.putBoolean(EXTRA_TRANSIENT_STATE, mTransientShown);
         if (mNavigationBarView != null) {
             mNavigationBarView.getLightTransitionsController().saveState(outState);
@@ -889,8 +898,9 @@
     }
 
     @Override
-    public void onSystemBarAppearanceChanged(int displayId, @Appearance int appearance,
-            AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme) {
+    public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
+            AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
+            @Behavior int behavior, boolean isFullscreen) {
         if (displayId != mDisplayId) {
             return;
         }
@@ -906,6 +916,10 @@
             mLightBarController.onNavigationBarAppearanceChanged(appearance, nbModeChanged,
                     mNavigationBarMode, navbarColorManagedByIme);
         }
+        if (mBehavior != behavior) {
+            mBehavior = behavior;
+            updateSystemUiStateFlags(-1);
+        }
     }
 
     @Override
@@ -1319,6 +1333,8 @@
                 .setFlag(SYSUI_STATE_NAV_BAR_HIDDEN, !isNavBarWindowVisible())
                 .setFlag(SYSUI_STATE_IME_SHOWING,
                         (mNavigationIconHints & NAVIGATION_HINT_BACK_ALT) != 0)
+                .setFlag(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY,
+                        allowSystemGestureIgnoringBarVisibility())
                 .commitUpdate(mDisplayId);
         registerAction(clickable, SystemActions.SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON);
         registerAction(longClickable, SystemActions.SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON_CHOOSER);
@@ -1421,6 +1437,10 @@
         return mNavigationBarWindowState == WINDOW_STATE_SHOWING;
     }
 
+    private boolean allowSystemGestureIgnoringBarVisibility() {
+        return mBehavior != BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
+    }
+
     /**
      * Checks current navigation bar mode and make transitions.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 5eba147..9e7ed0f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -686,11 +686,12 @@
      */
     protected void updateMediaHostContentMargins(ViewGroup mediaHostView) {
         if (mUsingMediaPlayer) {
-            int marginStart = mContentMarginStart;
+            int marginStart = 0;
+            int marginEnd = 0;
             if (mUsingHorizontalLayout) {
-                marginStart = 0;
+                marginEnd = mContentMarginEnd;
             }
-            updateMargins(mediaHostView, marginStart, mContentMarginEnd);
+            updateMargins(mediaHostView, marginStart, marginEnd);
         }
     }
 
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 ba71fa6..9b3775e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -30,6 +30,7 @@
 import com.android.systemui.qs.tiles.AirplaneModeTile;
 import com.android.systemui.qs.tiles.BatterySaverTile;
 import com.android.systemui.qs.tiles.BluetoothTile;
+import com.android.systemui.qs.tiles.CameraToggleTile;
 import com.android.systemui.qs.tiles.CastTile;
 import com.android.systemui.qs.tiles.CellularTile;
 import com.android.systemui.qs.tiles.ColorInversionTile;
@@ -39,6 +40,7 @@
 import com.android.systemui.qs.tiles.HotspotTile;
 import com.android.systemui.qs.tiles.InternetTile;
 import com.android.systemui.qs.tiles.LocationTile;
+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.ReduceBrightColorsTile;
@@ -83,6 +85,8 @@
     private final Provider<UiModeNightTile> mUiModeNightTileProvider;
     private final Provider<ScreenRecordTile> mScreenRecordTileProvider;
     private final Provider<ReduceBrightColorsTile> mReduceBrightColorsTileProvider;
+    private final Provider<CameraToggleTile> mCameraToggleTileProvider;
+    private final Provider<MicrophoneToggleTile> mMicrophoneToggleTileProvider;
 
     private final Lazy<QSHost> mQsHostLazy;
     private final Provider<CustomTile.Builder> mCustomTileBuilderProvider;
@@ -115,7 +119,9 @@
             Provider<GarbageMonitor.MemoryTile> memoryTileProvider,
             Provider<UiModeNightTile> uiModeNightTileProvider,
             Provider<ScreenRecordTile> screenRecordTileProvider,
-            Provider<ReduceBrightColorsTile> reduceBrightColorsTileProvider) {
+            Provider<ReduceBrightColorsTile> reduceBrightColorsTileProvider,
+            Provider<CameraToggleTile> cameraToggleTileProvider,
+            Provider<MicrophoneToggleTile> microphoneToggleTileProvider) {
         mQsHostLazy = qsHostLazy;
         mCustomTileBuilderProvider = customTileBuilderProvider;
 
@@ -143,6 +149,8 @@
         mUiModeNightTileProvider = uiModeNightTileProvider;
         mScreenRecordTileProvider = screenRecordTileProvider;
         mReduceBrightColorsTileProvider = reduceBrightColorsTileProvider;
+        mCameraToggleTileProvider = cameraToggleTileProvider;
+        mMicrophoneToggleTileProvider = microphoneToggleTileProvider;
     }
 
     public QSTile createTile(String tileSpec) {
@@ -198,6 +206,10 @@
                 return mScreenRecordTileProvider.get();
             case "reduce_brightness":
                 return mReduceBrightColorsTileProvider.get();
+            case "cameratoggle":
+                return mCameraToggleTileProvider.get();
+            case "mictoggle":
+                return mMicrophoneToggleTileProvider.get();
         }
 
         // Custom tiles
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
new file mode 100644
index 0000000..98740a2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
@@ -0,0 +1,80 @@
+/*
+ * 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.qs.tiles;
+
+import static android.service.SensorPrivacyIndividualEnabledSensorProto.CAMERA;
+
+import static com.android.systemui.DejankUtils.whitelistIpcs;
+
+import android.annotation.StringRes;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.DeviceConfig;
+
+import androidx.annotation.DrawableRes;
+import androidx.annotation.NonNull;
+
+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.statusbar.StatusBarStateController;
+import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
+
+import javax.inject.Inject;
+
+public class CameraToggleTile extends SensorPrivacyToggleTile {
+
+    @Inject
+    protected CameraToggleTile(QSHost host,
+            @Background Looper backgroundLooper,
+            @Main Handler mainHandler,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger,
+            IndividualSensorPrivacyController sensorPrivacyController) {
+        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
+                activityStarter, qsLogger, sensorPrivacyController);
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return /*getHost().getContext().getPackageManager().hasSystemFeature(FEATURE_CAMERA_TOGGLE)
+                && */whitelistIpcs(() -> DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
+                "camera_toggle_enabled",
+                false));
+    }
+
+    @Override
+    public @DrawableRes int getIconRes() {
+        return R.drawable.ic_camera_blocked;
+    }
+
+    @Override
+    public @NonNull CharSequence getTileLabel() {
+        return mContext.getString(R.string.quick_settings_camera_label);
+    }
+
+    @Override
+    public int getSensorId() {
+        return CAMERA;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
new file mode 100644
index 0000000..8cc0d7b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
@@ -0,0 +1,78 @@
+/*
+ * 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.qs.tiles;
+
+import static android.service.SensorPrivacyIndividualEnabledSensorProto.MICROPHONE;
+
+import static com.android.systemui.DejankUtils.whitelistIpcs;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.DeviceConfig;
+
+import androidx.annotation.DrawableRes;
+import androidx.annotation.NonNull;
+
+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.statusbar.StatusBarStateController;
+import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
+
+import javax.inject.Inject;
+
+public class MicrophoneToggleTile extends SensorPrivacyToggleTile {
+
+    @Inject
+    protected MicrophoneToggleTile(QSHost host,
+            @Background Looper backgroundLooper,
+            @Main Handler mainHandler,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger,
+            IndividualSensorPrivacyController sensorPrivacyController) {
+        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
+                activityStarter, qsLogger, sensorPrivacyController);
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return whitelistIpcs(() -> DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
+                "mic_toggle_enabled",
+                false));
+    }
+
+    @Override
+    public @DrawableRes int getIconRes() {
+        return R.drawable.ic_mic_blocked;
+    }
+
+    @Override
+    public @NonNull CharSequence getTileLabel() {
+        return mContext.getString(R.string.quick_settings_mic_label);
+    }
+
+    @Override
+    public int getSensorId() {
+        return MICROPHONE;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java
new file mode 100644
index 0000000..12205d6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java
@@ -0,0 +1,112 @@
+/*
+ * 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.qs.tiles;
+
+import android.content.Intent;
+import android.hardware.SensorPrivacyManager.IndividualSensor;
+import android.os.Handler;
+import android.os.Looper;
+import android.service.quicksettings.Tile;
+import android.widget.Switch;
+
+import androidx.annotation.DrawableRes;
+
+import com.android.internal.logging.MetricsLogger;
+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.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.policy.IndividualSensorPrivacyController;
+
+/**
+ * Superclass to toggle individual sensor privacy via quick settings tiles
+ */
+public abstract class SensorPrivacyToggleTile extends QSTileImpl<QSTile.BooleanState> implements
+        IndividualSensorPrivacyController.Callback {
+
+    private IndividualSensorPrivacyController mSensorPrivacyController;
+
+    /**
+     * @return Id of the sensor that will be toggled
+     */
+    public abstract @IndividualSensor int getSensorId();
+
+    /**
+     * @return icon for the QS tile
+     */
+    public abstract @DrawableRes int getIconRes();
+
+    protected SensorPrivacyToggleTile(QSHost host,
+            @Background Looper backgroundLooper,
+            @Main Handler mainHandler,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger,
+            IndividualSensorPrivacyController sensorPrivacyController) {
+        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
+                activityStarter, qsLogger);
+        mSensorPrivacyController = sensorPrivacyController;
+        mSensorPrivacyController.observe(getLifecycle(), this);
+    }
+
+    @Override
+    public BooleanState newTileState() {
+        return new BooleanState();
+    }
+
+    @Override
+    protected void handleClick() {
+        mSensorPrivacyController.setSensorBlocked(getSensorId(),
+                !mSensorPrivacyController.isSensorBlocked(getSensorId()));
+    }
+
+    @Override
+    protected void handleUpdateState(BooleanState state, Object arg) {
+        boolean isBlocked = arg == null ? mSensorPrivacyController.isSensorBlocked(getSensorId())
+                : (boolean) arg;
+
+        state.icon = ResourceIcon.get(getIconRes());
+        state.state = isBlocked ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+        state.value = isBlocked;
+        state.label = getTileLabel();
+        state.handlesLongClick = false;
+        state.contentDescription = state.label;
+        state.expandedAccessibilityClassName = Switch.class.getName();
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return 0;
+    }
+
+    @Override
+    public Intent getLongClickIntent() {
+        return null;
+    }
+
+    @Override
+    public void onSensorBlockedChanged(int sensor, boolean blocked) {
+        if (sensor == getSensorId()) {
+            refreshState(blocked);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 54e30af..760ebad 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -56,12 +56,14 @@
 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;
 
@@ -86,6 +88,7 @@
 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;
@@ -93,9 +96,9 @@
 import com.android.systemui.statusbar.policy.CallbackController;
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
 import com.android.wm.shell.onehanded.OneHanded;
-import com.android.wm.shell.onehanded.OneHandedEvents;
 import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.pip.PipAnimationController;
+import com.android.wm.shell.transition.Transitions;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -142,6 +145,7 @@
     private final ScreenshotHelper mScreenshotHelper;
     private final Optional<OneHanded> mOneHandedOptional;
     private final CommandQueue mCommandQueue;
+    private final Transitions mShellTransitions;
 
     private Region mActiveNavBarRegion;
 
@@ -158,6 +162,7 @@
     private float mWindowCornerRadius;
     private boolean mSupportsRoundedCornersOnWindows;
     private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
+    private final ArraySet<IRemoteTransition> mRemoteTransitions = new ArraySet<>();
 
     @VisibleForTesting
     public ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
@@ -463,8 +468,7 @@
             }
             final long token = Binder.clearCallingIdentity();
             try {
-                mOneHandedOptional.ifPresent(oneHanded -> oneHanded.stopOneHanded(
-                                OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_GESTURE_OUT));
+                mOneHandedOptional.ifPresent(oneHanded -> oneHanded.stopOneHanded());
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -530,6 +534,31 @@
             }
         }
 
+        @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);
+            }
+        }
+
         private boolean verifyCaller(String reason) {
             final int callerId = Binder.getCallingUserHandle().getIdentifier();
             if (callerId != mCurrentBoundedUserId) {
@@ -639,7 +668,8 @@
             Optional<LegacySplitScreen> splitScreenOptional,
             Optional<Lazy<StatusBar>> statusBarOptionalLazy,
             Optional<OneHanded> oneHandedOptional,
-            BroadcastDispatcher broadcastDispatcher) {
+            BroadcastDispatcher broadcastDispatcher,
+            Transitions shellTransitions) {
         super(broadcastDispatcher);
         mContext = context;
         mPipOptional = pipOptional;
@@ -658,6 +688,7 @@
         mSysUiState = sysUiState;
         mSysUiState.addCallback(this::notifySystemUiStateFlags);
         mOneHandedOptional = oneHandedOptional;
+        mShellTransitions = shellTransitions;
 
         // Assumes device always starts with back button until launcher tells it that it does not
         mNavBarButtonAlpha = 1.0f;
@@ -806,6 +837,12 @@
         // Clean up the minimized state if launcher dies
         mSplitScreenOptional.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/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
index db2750b..9dce191 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
@@ -47,7 +47,7 @@
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
 import com.android.systemui.R;
 import com.android.systemui.SystemUIFactory;
-import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ShareTransition;
+import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ActionTransition;
 
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
@@ -79,13 +79,13 @@
     private final String mScreenshotId;
     private final boolean mSmartActionsEnabled;
     private final Random mRandom = new Random();
-    private final Supplier<ShareTransition> mSharedElementTransition;
+    private final Supplier<ActionTransition> mSharedElementTransition;
     private final ImageExporter mImageExporter;
 
     SaveImageInBackgroundTask(Context context, ImageExporter exporter,
             ScreenshotSmartActions screenshotSmartActions,
             ScreenshotController.SaveImageInBackgroundData data,
-            Supplier<ShareTransition> sharedElementTransition) {
+            Supplier<ActionTransition> sharedElementTransition) {
         mContext = context;
         mScreenshotSmartActions = screenshotSmartActions;
         mImageData = new ScreenshotController.SavedImageData();
@@ -150,7 +150,7 @@
             mImageData.uri = uri;
             mImageData.smartActions = smartActions;
             mImageData.shareTransition = createShareAction(mContext, mContext.getResources(), uri);
-            mImageData.editAction = createEditAction(mContext, mContext.getResources(), uri);
+            mImageData.editTransition = createEditAction(mContext, mContext.getResources(), uri);
             mImageData.deleteAction = createDeleteAction(mContext, mContext.getResources(), uri);
 
             mParams.mActionsReadyListener.onActionsReady(mImageData);
@@ -204,9 +204,9 @@
      * Assumes that the action intent is sent immediately after being supplied.
      */
     @VisibleForTesting
-    Supplier<ShareTransition> createShareAction(Context context, Resources r, Uri uri) {
+    Supplier<ActionTransition> createShareAction(Context context, Resources r, Uri uri) {
         return () -> {
-            ShareTransition transition = mSharedElementTransition.get();
+            ActionTransition transition = mSharedElementTransition.get();
 
             // Note: Both the share and edit actions are proxied through ActionProxyReceiver in
             // order to do some common work like dismissing the keyguard and sending
@@ -259,52 +259,57 @@
                     Icon.createWithResource(r, R.drawable.ic_screenshot_share),
                     r.getString(com.android.internal.R.string.share), shareAction);
 
-            transition.shareAction = shareActionBuilder.build();
+            transition.action = shareActionBuilder.build();
             return transition;
         };
     }
 
     @VisibleForTesting
-    Notification.Action createEditAction(Context context, Resources r, Uri uri) {
-        // Note: Both the share and edit actions are proxied through ActionProxyReceiver in
-        // order to do some common work like dismissing the keyguard and sending
-        // closeSystemWindows
+    Supplier<ActionTransition> createEditAction(Context context, Resources r, Uri uri) {
+        return () -> {
+            ActionTransition transition = mSharedElementTransition.get();
+            // Note: Both the share and edit actions are proxied through ActionProxyReceiver in
+            // order to do some common work like dismissing the keyguard and sending
+            // closeSystemWindows
 
-        // Create an edit intent, if a specific package is provided as the editor, then
-        // launch that directly
-        String editorPackage = context.getString(R.string.config_screenshotEditor);
-        Intent editIntent = new Intent(Intent.ACTION_EDIT);
-        if (!TextUtils.isEmpty(editorPackage)) {
-            editIntent.setComponent(ComponentName.unflattenFromString(editorPackage));
-        }
-        editIntent.setDataAndType(uri, "image/png");
-        editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-        editIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
-        editIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+            // Create an edit intent, if a specific package is provided as the editor, then
+            // launch that directly
+            String editorPackage = context.getString(R.string.config_screenshotEditor);
+            Intent editIntent = new Intent(Intent.ACTION_EDIT);
+            if (!TextUtils.isEmpty(editorPackage)) {
+                editIntent.setComponent(ComponentName.unflattenFromString(editorPackage));
+            }
+            editIntent.setDataAndType(uri, "image/png");
+            editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+            editIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+            editIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
 
-        PendingIntent pendingIntent = PendingIntent.getActivityAsUser(context, 0,
-                editIntent, PendingIntent.FLAG_IMMUTABLE, null, UserHandle.CURRENT);
+            PendingIntent pendingIntent = PendingIntent.getActivityAsUser(
+                    context, 0, editIntent, PendingIntent.FLAG_IMMUTABLE,
+                    transition.bundle, UserHandle.CURRENT);
 
-        // Make sure pending intents for the system user are still unique across users
-        // by setting the (otherwise unused) request code to the current user id.
-        int requestCode = mContext.getUserId();
+            // Make sure pending intents for the system user are still unique across users
+            // by setting the (otherwise unused) request code to the current user id.
+            int requestCode = mContext.getUserId();
 
-        // Create a edit action
-        PendingIntent editAction = PendingIntent.getBroadcastAsUser(context, requestCode,
-                new Intent(context, ActionProxyReceiver.class)
-                        .putExtra(ScreenshotController.EXTRA_ACTION_INTENT, pendingIntent)
-                        .putExtra(ScreenshotController.EXTRA_ID, mScreenshotId)
-                        .putExtra(ScreenshotController.EXTRA_SMART_ACTIONS_ENABLED,
-                                mSmartActionsEnabled)
-                        .setAction(Intent.ACTION_EDIT)
-                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
-                PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
-                UserHandle.SYSTEM);
-        Notification.Action.Builder editActionBuilder = new Notification.Action.Builder(
-                Icon.createWithResource(r, R.drawable.ic_screenshot_edit),
-                r.getString(com.android.internal.R.string.screenshot_edit), editAction);
+            // Create a edit action
+            PendingIntent editAction = PendingIntent.getBroadcastAsUser(context, requestCode,
+                    new Intent(context, ActionProxyReceiver.class)
+                            .putExtra(ScreenshotController.EXTRA_ACTION_INTENT, pendingIntent)
+                            .putExtra(ScreenshotController.EXTRA_ID, mScreenshotId)
+                            .putExtra(ScreenshotController.EXTRA_SMART_ACTIONS_ENABLED,
+                                    mSmartActionsEnabled)
+                            .setAction(Intent.ACTION_EDIT)
+                            .addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
+                    PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
+                    UserHandle.SYSTEM);
+            Notification.Action.Builder editActionBuilder = new Notification.Action.Builder(
+                    Icon.createWithResource(r, R.drawable.ic_screenshot_edit),
+                    r.getString(com.android.internal.R.string.screenshot_edit), editAction);
 
-        return editActionBuilder.build();
+            transition.action = editActionBuilder.build();
+            return transition;
+        };
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 7d57799..d77d1ea 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -81,7 +81,7 @@
 import com.android.systemui.R;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ShareTransition;
+import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ActionTransition;
 import com.android.systemui.util.DeviceConfigProxy;
 
 import java.util.List;
@@ -115,17 +115,17 @@
      */
     static class SavedImageData {
         public Uri uri;
-        public Supplier<ShareTransition> shareTransition;
-        public Notification.Action editAction;
+        public Supplier<ActionTransition> shareTransition;
+        public Supplier<ActionTransition> editTransition;
         public Notification.Action deleteAction;
         public List<Notification.Action> smartActions;
 
         /**
-         * POD for shared element transition to share sheet.
+         * POD for shared element transition.
          */
-        static class ShareTransition {
+        static class ActionTransition {
             public Bundle bundle;
-            public Notification.Action shareAction;
+            public Notification.Action action;
             public Runnable onCancelRunnable;
         }
 
@@ -135,7 +135,7 @@
         public void reset() {
             uri = null;
             shareTransition = null;
-            editAction = null;
+            editTransition = null;
             deleteAction = null;
             smartActions = null;
         }
@@ -352,6 +352,10 @@
         }
     }
 
+    boolean isPendingSharedTransition() {
+        return mScreenshotView.isPendingSharedTransition();
+    }
+
     /**
      * Release the constructed window context.
      */
@@ -626,7 +630,7 @@
         }
 
         mSaveInBgTask = new SaveImageInBackgroundTask(mContext, mImageExporter,
-                mScreenshotSmartActions, data, getShareTransitionSupplier());
+                mScreenshotSmartActions, data, getActionTransitionSupplier());
         mSaveInBgTask.execute();
     }
 
@@ -680,7 +684,7 @@
      * Supplies the necessary bits for the shared element transition to share sheet.
      * Note that once supplied, the action intent to share must be sent immediately after.
      */
-    private Supplier<ShareTransition> getShareTransitionSupplier() {
+    private Supplier<ActionTransition> getActionTransitionSupplier() {
         return () -> {
             ExitTransitionCallbacks cb = new ExitTransitionCallbacks() {
                 @Override
@@ -689,7 +693,13 @@
                 }
 
                 @Override
-                public void onFinish() { }
+                public void hideSharedElements() {
+                    resetScreenshotView();
+                }
+
+                @Override
+                public void onFinish() {
+                }
             };
 
             Pair<ActivityOptions, ExitTransitionCoordinator> transition =
@@ -698,7 +708,7 @@
                                     ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME));
             transition.second.startExit();
 
-            ShareTransition supply = new ShareTransition();
+            ActionTransition supply = new ActionTransition();
             supply.bundle = transition.first.toBundle();
             supply.onCancelRunnable = () -> ActivityOptions.stopSharedElementAnimation(mWindow);
             return supply;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index 41c2098..211f507 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -74,7 +74,7 @@
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.R;
-import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ShareTransition;
+import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ActionTransition;
 import com.android.systemui.shared.system.QuickStepContract;
 
 import java.util.ArrayList;
@@ -106,7 +106,6 @@
     private static final long SCREENSHOT_DISMISS_Y_DURATION_MS = 350;
     private static final long SCREENSHOT_DISMISS_ALPHA_DURATION_MS = 183;
     private static final long SCREENSHOT_DISMISS_ALPHA_OFFSET_MS = 50; // delay before starting fade
-    private static final long SCREENSHOT_DISMISS_SHARE_OFFSET_MS = 300; // delay after share clicked
     private static final float SCREENSHOT_ACTIONS_START_SCALE_X = .7f;
     private static final float ROUNDED_CORNER_RADIUS = .05f;
     private static final int SWIPE_PADDING_DP = 12; // extra padding around views to allow swipe
@@ -142,7 +141,7 @@
     private UiEventLogger mUiEventLogger;
     private ScreenshotViewCallback mCallbacks;
     private Animator mDismissAnimation;
-    private boolean mIgnoreDismiss;
+    private boolean mPendingSharedTransition;
 
     private final ArrayList<ScreenshotActionChip> mSmartChips = new ArrayList<>();
     private PendingInteraction mPendingInteraction;
@@ -296,6 +295,10 @@
         requestFocus();
     }
 
+    View getScreenshotPreview() {
+        return mScreenshotPreview;
+    }
+
     /**
      * Set up the logger and callback on dismissal.
      *
@@ -535,44 +538,22 @@
         });
         return animator;
     }
-    protected View getScreenshotPreview() {
-        return mScreenshotPreview;
-    }
 
     void setChipIntents(ScreenshotController.SavedImageData imageData) {
         mShareChip.setOnClickListener(v -> {
-            ShareTransition transition = imageData.shareTransition.get();
-            try {
-                mIgnoreDismiss = true;
-                transition.shareAction.actionIntent.send();
-                mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SHARE_TAPPED);
-
-                // Ensures that we delay dismissing until transition has started.
-                postDelayed(() -> {
-                    mIgnoreDismiss = false;
-                    animateDismissal();
-                }, SCREENSHOT_DISMISS_SHARE_OFFSET_MS);
-            } catch (PendingIntent.CanceledException e) {
-                mIgnoreDismiss = false;
-                if (transition.onCancelRunnable != null) {
-                    transition.onCancelRunnable.run();
-                }
-                Log.e(TAG, "Share intent cancelled", e);
-            }
+            mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SHARE_TAPPED);
+            startSharedTransition(
+                    imageData.shareTransition.get());
         });
-        mEditChip.setPendingIntent(imageData.editAction.actionIntent,
-                () -> {
-                    mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_EDIT_TAPPED);
-                    animateDismissal();
-                });
+        mEditChip.setOnClickListener(v -> {
+            mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_EDIT_TAPPED);
+            startSharedTransition(
+                    imageData.editTransition.get());
+        });
         mScreenshotPreview.setOnClickListener(v -> {
-            try {
-                imageData.editAction.actionIntent.send();
-            } catch (PendingIntent.CanceledException e) {
-                Log.e(TAG, "PendingIntent was cancelled", e);
-            }
             mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_PREVIEW_TAPPED);
-            animateDismissal();
+            startSharedTransition(
+                    imageData.editTransition.get());
         });
 
         if (mPendingInteraction != null) {
@@ -611,14 +592,15 @@
         return (mDismissAnimation != null && mDismissAnimation.isRunning());
     }
 
+    boolean isPendingSharedTransition() {
+        return mPendingSharedTransition;
+    }
+
     void animateDismissal() {
-        animateDismissal(createScreenshotDismissAnimation());
+        animateDismissal(createScreenshotTranslateDismissAnimation());
     }
 
     private void animateDismissal(Animator dismissAnimation) {
-        if (mIgnoreDismiss) {
-            return;
-        }
         if (DEBUG_WINDOW) {
             Log.d(TAG, "removing OnComputeInternalInsetsListener");
         }
@@ -671,6 +653,7 @@
         getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
         // Clear any references to the bitmap
         mScreenshotPreview.setImageDrawable(null);
+        mPendingSharedTransition = false;
         mActionsContainerBackground.setVisibility(View.GONE);
         mActionsContainer.setVisibility(View.GONE);
         mBackgroundProtection.setAlpha(0f);
@@ -698,7 +681,23 @@
         mScreenshotSelectorView.stop();
     }
 
-    private AnimatorSet createScreenshotDismissAnimation() {
+    private void startSharedTransition(ActionTransition transition) {
+        try {
+            mPendingSharedTransition = true;
+            transition.action.actionIntent.send();
+
+            // fade out non-preview UI
+            createScreenshotFadeDismissAnimation().start();
+        } catch (PendingIntent.CanceledException e) {
+            mPendingSharedTransition = false;
+            if (transition.onCancelRunnable != null) {
+                transition.onCancelRunnable.run();
+            }
+            Log.e(TAG, "Intent cancelled", e);
+        }
+    }
+
+    private AnimatorSet createScreenshotTranslateDismissAnimation() {
         ValueAnimator alphaAnim = ValueAnimator.ofFloat(0, 1);
         alphaAnim.setStartDelay(SCREENSHOT_DISMISS_ALPHA_OFFSET_MS);
         alphaAnim.setDuration(SCREENSHOT_DISMISS_ALPHA_DURATION_MS);
@@ -725,6 +724,19 @@
         return animSet;
     }
 
+    private ValueAnimator createScreenshotFadeDismissAnimation() {
+        ValueAnimator alphaAnim = ValueAnimator.ofFloat(0, 1);
+        alphaAnim.addUpdateListener(animation -> {
+            float alpha = 1 - animation.getAnimatedFraction();
+            mDismissButton.setAlpha(alpha);
+            mActionsContainerBackground.setAlpha(alpha);
+            mActionsContainer.setAlpha(alpha);
+            mBackgroundProtection.setAlpha(alpha);
+        });
+        alphaAnim.setDuration(600);
+        return alphaAnim;
+    }
+
     /**
      * Create a drawable using the size of the bitmap and insets as the fractional inset parameters.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index c33bbc5..144ad39 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -72,7 +72,9 @@
                 if (DEBUG_DISMISS) {
                     Log.d(TAG, "Received ACTION_CLOSE_SYSTEM_DIALOGS");
                 }
-                mScreenshot.dismissScreenshot(false);
+                if (!mScreenshot.isPendingSharedTransition()) {
+                    mScreenshot.dismissScreenshot(false);
+                }
             }
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index fbb8042..c4fa6df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -34,7 +34,6 @@
 import android.app.StatusBarManager.WindowVisibleState;
 import android.content.ComponentName;
 import android.content.Context;
-import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.IBiometricSysuiReceiver;
 import android.hardware.biometrics.PromptInfo;
 import android.hardware.display.DisplayManager;
@@ -50,6 +49,7 @@
 import android.util.SparseArray;
 import android.view.InsetsState.InternalInsetsType;
 import android.view.WindowInsetsController.Appearance;
+import android.view.WindowInsetsController.Behavior;
 
 import androidx.annotation.NonNull;
 
@@ -90,7 +90,7 @@
     private static final int MSG_EXPAND_NOTIFICATIONS              = 3 << MSG_SHIFT;
     private static final int MSG_COLLAPSE_PANELS                   = 4 << MSG_SHIFT;
     private static final int MSG_EXPAND_SETTINGS                   = 5 << MSG_SHIFT;
-    private static final int MSG_SYSTEM_BAR_APPEARANCE_CHANGED     = 6 << MSG_SHIFT;
+    private static final int MSG_SYSTEM_BAR_CHANGED                = 6 << MSG_SHIFT;
     private static final int MSG_DISPLAY_READY                     = 7 << MSG_SHIFT;
     private static final int MSG_SHOW_IME_BUTTON                   = 8 << MSG_SHIFT;
     private static final int MSG_TOGGLE_RECENT_APPS                = 9 << MSG_SHIFT;
@@ -131,17 +131,16 @@
     private static final int MSG_RECENTS_ANIMATION_STATE_CHANGED   = 47 << MSG_SHIFT;
     private static final int MSG_SHOW_TRANSIENT                    = 48 << MSG_SHIFT;
     private static final int MSG_ABORT_TRANSIENT                   = 49 << MSG_SHIFT;
-    private static final int MSG_TOP_APP_WINDOW_CHANGED            = 50 << MSG_SHIFT;
-    private static final int MSG_SHOW_INATTENTIVE_SLEEP_WARNING    = 51 << MSG_SHIFT;
-    private static final int MSG_DISMISS_INATTENTIVE_SLEEP_WARNING = 52 << MSG_SHIFT;
-    private static final int MSG_SHOW_TOAST                        = 53 << MSG_SHIFT;
-    private static final int MSG_HIDE_TOAST                        = 54 << MSG_SHIFT;
-    private static final int MSG_TRACING_STATE_CHANGED             = 55 << MSG_SHIFT;
-    private static final int MSG_SUPPRESS_AMBIENT_DISPLAY          = 56 << MSG_SHIFT;
-    private static final int MSG_REQUEST_WINDOW_MAGNIFICATION_CONNECTION = 57 << MSG_SHIFT;
-    private static final int MSG_HANDLE_WINDOW_MANAGER_LOGGING_COMMAND = 58 << MSG_SHIFT;
+    private static final int MSG_SHOW_INATTENTIVE_SLEEP_WARNING    = 50 << MSG_SHIFT;
+    private static final int MSG_DISMISS_INATTENTIVE_SLEEP_WARNING = 51 << MSG_SHIFT;
+    private static final int MSG_SHOW_TOAST                        = 52 << MSG_SHIFT;
+    private static final int MSG_HIDE_TOAST                        = 53 << MSG_SHIFT;
+    private static final int MSG_TRACING_STATE_CHANGED             = 54 << MSG_SHIFT;
+    private static final int MSG_SUPPRESS_AMBIENT_DISPLAY          = 55 << MSG_SHIFT;
+    private static final int MSG_REQUEST_WINDOW_MAGNIFICATION_CONNECTION = 56 << MSG_SHIFT;
+    private static final int MSG_HANDLE_WINDOW_MANAGER_LOGGING_COMMAND = 57 << MSG_SHIFT;
     //TODO(b/169175022) Update name and when feature name is locked.
-    private static final int MSG_EMERGENCY_ACTION_LAUNCH_GESTURE      = 59 << MSG_SHIFT;
+    private static final int MSG_EMERGENCY_ACTION_LAUNCH_GESTURE      = 58 << MSG_SHIFT;
 
     public static final int FLAG_EXCLUDE_NONE = 0;
     public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -308,10 +307,11 @@
         default void onRecentsAnimationStateChanged(boolean running) { }
 
         /**
-         * @see IStatusBar#onSystemBarAppearanceChanged(int, int, AppearanceRegion[], boolean).
+         * @see IStatusBar#onSystemBarAttributesChanged.
          */
-        default void onSystemBarAppearanceChanged(int displayId, @Appearance int appearance,
-                AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme) { }
+        default void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
+                AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
+                @Behavior int behavior, boolean isFullscreen) { }
 
         /**
          * @see IStatusBar#showTransient(int, int[]).
@@ -324,12 +324,6 @@
         default void abortTransient(int displayId, @InternalInsetsType int[] types) { }
 
         /**
-         * @see IStatusBar#topAppWindowChanged(int, boolean, boolean).
-         */
-        default void topAppWindowChanged(int displayId, boolean isFullscreen, boolean isImmersive) {
-        }
-
-        /**
          * Called to notify System UI that a warning about the device going to sleep
          * due to prolonged user inactivity should be shown.
          */
@@ -547,18 +541,6 @@
     }
 
     @Override
-    public void topAppWindowChanged(int displayId, boolean isFullscreen, boolean isImmersive) {
-        synchronized (mLock) {
-            SomeArgs args = SomeArgs.obtain();
-            args.argi1 = displayId;
-            args.argi2 = isFullscreen ? 1 : 0;
-            args.argi3 = isImmersive ? 1 : 0;
-            mHandler.obtainMessage(MSG_TOP_APP_WINDOW_CHANGED, args).sendToTarget();
-        }
-
-    }
-
-    @Override
     public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
             boolean showImeSwitcher, boolean isMultiClientImeEnabled) {
         synchronized (mLock) {
@@ -969,15 +951,18 @@
     }
 
     @Override
-    public void onSystemBarAppearanceChanged(int displayId, @Appearance int appearance,
-            AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme) {
+    public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
+            AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
+            @Behavior int behavior, boolean isFullscreen) {
         synchronized (mLock) {
             SomeArgs args = SomeArgs.obtain();
             args.argi1 = displayId;
             args.argi2 = appearance;
             args.argi3 = navbarColorManagedByIme ? 1 : 0;
             args.arg1 = appearanceRegions;
-            mHandler.obtainMessage(MSG_SYSTEM_BAR_APPEARANCE_CHANGED, args).sendToTarget();
+            args.argi4 = behavior;
+            args.argi5 = isFullscreen ? 1 : 0;
+            mHandler.obtainMessage(MSG_SYSTEM_BAR_CHANGED, args).sendToTarget();
         }
     }
 
@@ -1328,11 +1313,12 @@
                         mCallbacks.get(i).onRecentsAnimationStateChanged(msg.arg1 > 0);
                     }
                     break;
-                case MSG_SYSTEM_BAR_APPEARANCE_CHANGED:
+                case MSG_SYSTEM_BAR_CHANGED:
                     args = (SomeArgs) msg.obj;
                     for (int i = 0; i < mCallbacks.size(); i++) {
-                        mCallbacks.get(i).onSystemBarAppearanceChanged(args.argi1, args.argi2,
-                                (AppearanceRegion[]) args.arg1, args.argi3 == 1);
+                        mCallbacks.get(i).onSystemBarAttributesChanged(args.argi1, args.argi2,
+                                (AppearanceRegion[]) args.arg1, args.argi3 == 1, args.argi4,
+                                args.argi5 == 1);
                     }
                     args.recycle();
                     break;
@@ -1352,15 +1338,6 @@
                     }
                     break;
                 }
-                case MSG_TOP_APP_WINDOW_CHANGED: {
-                    args = (SomeArgs) msg.obj;
-                    for (int i = 0; i < mCallbacks.size(); i++) {
-                        mCallbacks.get(i).topAppWindowChanged(
-                                args.argi1, args.argi2 != 0, args.argi3 != 0);
-                    }
-                    args.recycle();
-                    break;
-                }
                 case MSG_SHOW_INATTENTIVE_SLEEP_WARNING:
                     for (int i = 0; i < mCallbacks.size(); i++) {
                         mCallbacks.get(i).showInattentiveSleepWarning();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index e944249..6ba5215 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -88,11 +88,6 @@
     private boolean mIsFullscreen = false;
 
     /**
-     * If the navigation bar can stay hidden when the display gets tapped.
-     */
-    private boolean mIsImmersive = false;
-
-    /**
      * If the device is currently pulsing (AOD2).
      */
     private boolean mPulsing;
@@ -360,13 +355,12 @@
     }
 
     @Override
-    public void setFullscreenState(boolean isFullscreen, boolean isImmersive) {
-        if (mIsFullscreen != isFullscreen || mIsImmersive != isImmersive) {
+    public void setFullscreenState(boolean isFullscreen) {
+        if (mIsFullscreen != isFullscreen) {
             mIsFullscreen = isFullscreen;
-            mIsImmersive = isImmersive;
             synchronized (mListeners) {
                 for (RankedListener rl : new ArrayList<>(mListeners)) {
-                    rl.mListener.onFullscreenStateChanged(isFullscreen, isImmersive);
+                    rl.mListener.onFullscreenStateChanged(isFullscreen, true /* isImmersive */);
                 }
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java
index 9f8fe35..a2e07b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java
@@ -121,7 +121,7 @@
     /**
      * Set the fullscreen state
      */
-    void setFullscreenState(boolean isFullscreen, boolean isImmersive);
+    void setFullscreenState(boolean isFullscreen);
 
     /**
      * Set pulsing
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 8223d97..a03fc13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.notification.row;
 
+import static android.app.Notification.Action.SEMANTIC_ACTION_MARK_CONVERSATION_AS_PRIORITY;
 import static android.service.notification.NotificationListenerService.REASON_CANCEL;
 
 import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
@@ -1785,6 +1786,27 @@
         doLongClickCallback(x, y, menuItem);
     }
 
+    /**
+     * Perform a smart action which triggers a longpress (expose guts).
+     * Based on the semanticAction passed, may update the state of the guts view.
+     * @param semanticAction associated with this smart action click
+     */
+    public void doSmartActionClick(int x, int y, int semanticAction) {
+        createMenu();
+        NotificationMenuRowPlugin provider = getProvider();
+        MenuItem menuItem = null;
+        if (provider != null) {
+            menuItem = provider.getLongpressMenuItem(mContext);
+        }
+        if (SEMANTIC_ACTION_MARK_CONVERSATION_AS_PRIORITY == semanticAction
+                && menuItem.getGutsView() instanceof NotificationConversationInfo) {
+            NotificationConversationInfo info =
+                    (NotificationConversationInfo) menuItem.getGutsView();
+            info.setSelectedAction(NotificationConversationInfo.ACTION_FAVORITE);
+        }
+        doLongClickCallback(x, y, menuItem);
+    }
+
     private void doLongClickCallback(int x, int y, MenuItem menuItem) {
         if (mLongPressListener != null && menuItem != null) {
             mLongPressListener.onLongPress(this, x, y, menuItem);
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 1a2550b..adeba90 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
@@ -206,6 +206,7 @@
     }
 
     public void bindNotification(
+            @Action int selectedAction,
             ShortcutManager shortcutManager,
             PackageManager pm,
             INotificationManager iNotificationManager,
@@ -224,7 +225,8 @@
             @Background Handler bgHandler,
             OnConversationSettingsClickListener onConversationSettingsClickListener,
             Optional<BubblesManager> bubblesManagerOptional) {
-        mSelectedAction = -1;
+        mPressedApply = false;
+        mSelectedAction = selectedAction;
         mINotificationManager = iNotificationManager;
         mOnUserInteractionCallback = onUserInteractionCallback;
         mPackageName = pkg;
@@ -297,7 +299,8 @@
         settingsButton.setOnClickListener(getSettingsOnClickListener());
         settingsButton.setVisibility(settingsButton.hasOnClickListeners() ? VISIBLE : GONE);
 
-        updateToggleActions(getSelectedAction(), false);
+        updateToggleActions(mSelectedAction == -1 ? getPriority() : mSelectedAction,
+                false);
     }
 
     private void bindHeader() {
@@ -406,7 +409,7 @@
 
     @Override
     public void onFinishedClosing() {
-        // TODO: do we need to do anything here?
+        mSelectedAction = -1;
     }
 
     @Override
@@ -487,7 +490,7 @@
                 throw new IllegalArgumentException("Unrecognized behavior: " + mSelectedAction);
         }
 
-        boolean isAChange = getSelectedAction() != selectedAction;
+        boolean isAChange = getPriority() != selectedAction;
         TextView done = findViewById(R.id.done);
         done.setText(isAChange
                 ? R.string.inline_ok_button
@@ -498,6 +501,10 @@
     }
 
     int getSelectedAction() {
+        return mSelectedAction;
+    }
+
+    private int getPriority() {
         if (mNotificationChannel.getImportance() <= IMPORTANCE_LOW
                 && mNotificationChannel.getImportance() > IMPORTANCE_UNSPECIFIED) {
             return ACTION_MUTE;
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 2fd17a5..6a873b6 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
@@ -474,6 +474,7 @@
                         R.dimen.notification_guts_conversation_icon_size));
 
         notificationInfoView.bindNotification(
+                notificationInfoView.getSelectedAction(),
                 mShortcutManager,
                 pmUser,
                 mNotificationManager,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index 2c501cb..b5963ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -77,6 +77,7 @@
     private Runnable mOnPulseHeightChangedListener;
     private ExpandableNotificationRow mTrackedHeadsUpRow;
     private float mAppearFraction;
+    private boolean mIsShadeOpening;
 
     /** Tracks the state from AlertingNotificationManager#hasNotifications() */
     private boolean mHasAlertEntries;
@@ -96,6 +97,14 @@
         mBaseZHeight = getBaseHeight(mZDistanceBetweenElements);
     }
 
+    void setIsShadeOpening(boolean isOpening) {
+        mIsShadeOpening = isOpening;
+    }
+
+    public boolean isShadeOpening() {
+        return mIsShadeOpening;
+    }
+
     private static int getZDistanceBetweenElements(Context context) {
         return Math.max(1, context.getResources()
                 .getDimensionPixelSize(R.dimen.z_distance_between_notifications));
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 9e8385b..6abbc6b 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
@@ -550,6 +550,10 @@
         }
     }
 
+    void setIsShadeOpening(boolean isOpening) {
+        mAmbientState.setIsShadeOpening(isOpening);
+    }
+
     @Override
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     protected void onFinishInflate() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index f4d01f3..5126f55 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -271,6 +271,10 @@
         }
     };
 
+    public void setIsShadeOpening(boolean isOpening) {
+        mView.setIsShadeOpening(isOpening);
+    }
+
     private final OnMenuEventListener mMenuEventListener = new OnMenuEventListener() {
         @Override
         public void onMenuClicked(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java
index d27a3d5..7d13405 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java
@@ -22,7 +22,8 @@
 import android.animation.AnimatorListenerAdapter;
 import android.annotation.Nullable;
 import android.view.View;
-import android.view.WindowInsetsController;
+import android.view.WindowInsetsController.Appearance;
+import android.view.WindowInsetsController.Behavior;
 import android.view.WindowManager;
 import android.view.animation.AccelerateInterpolator;
 
@@ -52,7 +53,7 @@
     private final WindowManager mWindowManager;
 
     /** @see android.view.WindowInsetsController#setSystemBarsAppearance(int) */
-    @VisibleForTesting @WindowInsetsController.Appearance int mAppearance;
+    @VisibleForTesting @Appearance int mAppearance;
 
     private int mDisplayId;
     private View mLightsOutNotifView;
@@ -146,10 +147,9 @@
 
     private final CommandQueue.Callbacks mCallback = new CommandQueue.Callbacks() {
         @Override
-        public void onSystemBarAppearanceChanged(int displayId,
-                @WindowInsetsController.Appearance int appearance,
-                AppearanceRegion[] appearanceRegions,
-                boolean navbarColorManagedByIme) {
+        public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
+                AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
+                @Behavior int behavior, boolean isFullscreen) {
             if (displayId != mDisplayId) {
                 return;
             }
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 5e71671..d132abe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -2408,6 +2408,11 @@
     }
 
     @Override
+    protected void setIsShadeOpening(boolean isOpening) {
+        mNotificationStackScrollLayoutController.setIsShadeOpening(isOpening);
+    }
+
+    @Override
     protected void setOverExpansion(float overExpansion, boolean isPixels) {
         if (mConflictingQsExpansionGesture || mQsExpandImmediate) {
             return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index c106518..a1112dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -52,6 +52,9 @@
     public void go(int state) {
         if (DEBUG) LOG("go state: %d -> %d", mState, state);
         mState = state;
+        if (mPanel != null) {
+            mPanel.setIsShadeOpening(state == STATE_OPENING);
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index 62ded0a..da82986 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -740,6 +740,8 @@
      */
     protected abstract boolean isTrackingBlocked();
 
+    protected abstract void setIsShadeOpening(boolean isShadeOpening);
+
     protected abstract void setOverExpansion(float overExpansion, boolean isPixels);
 
     protected abstract void onHeightUpdated(float expandedHeight);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index f1b3cc5..fc1811b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -1005,6 +1005,7 @@
     }
 
     private void updateThemeColors() {
+        if (mScrimBehind == null) return;
         int background = Utils.getColorAttr(mScrimBehind.getContext(),
                 android.R.attr.colorBackgroundFloating).getDefaultColor();
         int accent = Utils.getColorAccent(mScrimBehind.getContext()).getDefaultColor();
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 8f23824..8ea173b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -112,6 +112,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowInsetsController.Appearance;
+import android.view.WindowInsetsController.Behavior;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityManager;
@@ -444,9 +445,6 @@
 
     private boolean mTransientShown;
 
-    private boolean mAppFullscreen;
-    private boolean mAppImmersive;
-
     private final DisplayMetrics mDisplayMetrics;
 
     // XXX: gesture research
@@ -574,6 +572,8 @@
     private NotificationEntry mDraggedDownEntry;
     private boolean mLaunchCameraWhenFinishedWaking;
     private boolean mLaunchCameraOnFinishedGoingToSleep;
+    private boolean mLaunchEmergencyActionWhenFinishedWaking;
+    private boolean mLaunchEmergencyActionOnFinishedGoingToSleep;
     private int mLastCameraLaunchSource;
     protected PowerManager.WakeLock mGestureWakeLock;
     private Vibrator mVibrator;
@@ -921,10 +921,8 @@
         if (containsType(result.mTransientBarTypes, ITYPE_STATUS_BAR)) {
             showTransientUnchecked();
         }
-        onSystemBarAppearanceChanged(mDisplayId, result.mAppearance, result.mAppearanceRegions,
-                result.mNavbarColorManagedByIme);
-        mAppFullscreen = result.mAppFullscreen;
-        mAppImmersive = result.mAppImmersive;
+        onSystemBarAttributesChanged(mDisplayId, result.mAppearance, result.mAppearanceRegions,
+                result.mNavbarColorManagedByIme, result.mBehavior, result.mAppFullscreen);
 
         // StatusBarManagerService has a back up of IME token and it's restored here.
         setImeWindowStatus(mDisplayId, result.mImeToken, result.mImeWindowVis,
@@ -2345,8 +2343,9 @@
     }
 
     @Override
-    public void onSystemBarAppearanceChanged(int displayId, @Appearance int appearance,
-            AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme) {
+    public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
+            AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
+            @Behavior int behavior, boolean isFullscreen) {
         if (displayId != mDisplayId) {
             return;
         }
@@ -2359,6 +2358,7 @@
                 mStatusBarMode, navbarColorManagedByIme);
 
         updateBubblesVisibility();
+        mStatusBarStateController.setFullscreenState(isFullscreen);
     }
 
     @Override
@@ -2432,16 +2432,6 @@
     }
 
     @Override
-    public void topAppWindowChanged(int displayId, boolean isFullscreen, boolean isImmersive) {
-        if (displayId != mDisplayId) {
-            return;
-        }
-        mAppFullscreen = isFullscreen;
-        mAppImmersive = isImmersive;
-        mStatusBarStateController.setFullscreenState(isFullscreen, isImmersive);
-    }
-
-    @Override
     public void showWirelessChargingAnimation(int batteryLevel) {
         showChargingAnimation(batteryLevel, UNKNOWN_BATTERY_LEVEL, 0);
     }
@@ -2551,16 +2541,6 @@
         }
     }
 
-    /** Returns whether the top activity is in fullscreen mode. */
-    public boolean inFullscreenMode() {
-        return mAppFullscreen;
-    }
-
-    /** Returns whether the top activity is in immersive mode. */
-    public boolean inImmersiveMode() {
-        return mAppImmersive;
-    }
-
     public static String viewInfo(View v) {
         return "[(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom()
                 + ") " + v.getWidth() + "x" + v.getHeight() + "]";
@@ -3844,6 +3824,14 @@
                 // is correct.
                 mHandler.post(() -> onCameraLaunchGestureDetected(mLastCameraLaunchSource));
             }
+
+            if (mLaunchEmergencyActionOnFinishedGoingToSleep) {
+                mLaunchEmergencyActionOnFinishedGoingToSleep = false;
+
+                // This gets executed before we will show Keyguard, so post it in order that the
+                // state is correct.
+                mHandler.post(() -> onEmergencyActionLaunchGestureDetected());
+            }
             updateIsKeyguard();
         }
 
@@ -3890,6 +3878,13 @@
                         false /* animate */, mLastCameraLaunchSource);
                 mLaunchCameraWhenFinishedWaking = false;
             }
+            if (mLaunchEmergencyActionWhenFinishedWaking) {
+                mLaunchEmergencyActionWhenFinishedWaking = false;
+                Intent emergencyIntent = getEmergencyActionIntent();
+                if (emergencyIntent != null) {
+                    mContext.startActivityAsUser(emergencyIntent, UserHandle.CURRENT);
+                }
+            }
             updateScrimController();
         }
     };
@@ -4027,20 +4022,65 @@
 
     @Override
     public void onEmergencyActionLaunchGestureDetected() {
-        // TODO (b/169793384) Polish the panic gesture to be just like its older brother, camera.
+        Intent emergencyIntent = getEmergencyActionIntent();
+
+        if (emergencyIntent == null) {
+            Log.wtf(TAG, "Couldn't find an app to process the emergency intent.");
+            return;
+        }
+
+        if (isGoingToSleep()) {
+            mLaunchEmergencyActionOnFinishedGoingToSleep = true;
+            return;
+        }
+
+        if (!mDeviceInteractive) {
+            mPowerManager.wakeUp(SystemClock.uptimeMillis(),
+                    PowerManager.WAKE_REASON_GESTURE,
+                    "com.android.systemui:EMERGENCY_GESTURE");
+        }
+        // TODO(b/169087248) Possibly add haptics here for emergency action. Currently disabled for
+        // app-side haptic experimentation.
+
+        if (!mStatusBarKeyguardViewManager.isShowing()) {
+            startActivityDismissingKeyguard(emergencyIntent,
+                    false /* onlyProvisioned */, true /* dismissShade */,
+                    true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0);
+            return;
+        }
+
+        if (!mDeviceInteractive) {
+            // Avoid flickering of the scrim when we instant launch the camera and the bouncer
+            // comes on.
+            mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
+        }
+
+        if (isWakingUpOrAwake()) {
+            if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
+                mStatusBarKeyguardViewManager.reset(true /* hide */);
+            }
+            mContext.startActivityAsUser(emergencyIntent, UserHandle.CURRENT);
+            return;
+        }
+        // We need to defer the emergency action launch until the screen comes on, since otherwise
+        // we will dismiss us too early since we are waiting on an activity to be drawn and
+        // incorrectly get notified because of the screen on event (which resumes and pauses
+        // some activities)
+        mLaunchEmergencyActionWhenFinishedWaking = true;
+    }
+
+    private @Nullable Intent getEmergencyActionIntent() {
         Intent emergencyIntent = new Intent(EmergencyGesture.ACTION_LAUNCH_EMERGENCY);
         PackageManager pm = mContext.getPackageManager();
         ResolveInfo resolveInfo = pm.resolveActivity(emergencyIntent, /*flags=*/0);
         if (resolveInfo == null) {
-            // TODO(b/171084088) Upgrade log to wtf when we have default app in main branch.
-            Log.d(TAG, "Couldn't find an app to process the emergency intent.");
-            return;
+            Log.wtf(TAG, "Couldn't find an app to process the emergency intent.");
+            return null;
         }
-
         emergencyIntent.setComponent(new ComponentName(resolveInfo.activityInfo.packageName,
                 resolveInfo.activityInfo.name));
         emergencyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        startActivity(emergencyIntent, /*dismissShade=*/true);
+        return emergencyIntent;
     }
 
     boolean isCameraAllowedByAdmin() {
@@ -4100,8 +4140,10 @@
             ScrimState state = mStatusBarKeyguardViewManager.bouncerNeedsScrimming()
                     ? ScrimState.BOUNCER_SCRIMMED : ScrimState.BOUNCER;
             mScrimController.transitionTo(state);
-        } else if (isInLaunchTransition() || mLaunchCameraWhenFinishedWaking
+        } else if (isInLaunchTransition()
+                || mLaunchCameraWhenFinishedWaking
                 || launchingAffordanceWithPreview) {
+            // TODO(b/170133395) Investigate whether Emergency Gesture flag should be included here.
             mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
         } else if (mBrightnessMirrorVisible) {
             mScrimController.transitionTo(ScrimState.BRIGHTNESS_MIRROR);
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 f0efed3..00acd7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -43,6 +43,7 @@
 import com.android.systemui.statusbar.StatusBarWifiView;
 import com.android.systemui.statusbar.StatusIconDisplayable;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
+import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.NoCallingIconState;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
 
 import java.util.List;
@@ -62,6 +63,10 @@
     public void setIcon(String slot, StatusBarIcon icon);
     public void setSignalIcon(String slot, WifiIconState state);
     public void setMobileIcons(String slot, List<MobileIconState> states);
+    /**
+     * Display the no calling & SMS icons.
+     */
+    void setNoCallingIcons(String slot, List<NoCallingIconState> 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 2870152..5e8d590 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -35,6 +35,7 @@
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.StatusIconDisplayable;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
+import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.NoCallingIconState;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
@@ -216,6 +217,29 @@
         }
     }
 
+    /**
+     * Accept a list of NoCallingIconStates, and show them in the same slot
+     * @param slot StatusBar slot
+     * @param states All of the no Calling & SMS icon states
+     */
+    @Override
+    public void setNoCallingIcons(String slot, List<NoCallingIconState> states) {
+        Slot noCallingSlot = getSlot(slot);
+        int slotIndex = getSlotIndex(slot);
+
+        for (NoCallingIconState state : states) {
+            StatusBarIconHolder holder = noCallingSlot.getHolderForTag(state.subId);
+            if (holder == null) {
+                holder = StatusBarIconHolder.fromNoCallingState(mContext, state);
+                holder.setVisible(state.visible);
+                setIcon(slotIndex, holder);
+            } else {
+                holder.setVisible(state.visible);
+                setIcon(slotIndex, holder);
+            }
+        }
+    }
+
     @Override
     public void setExternalIcon(String slot) {
         int viewIndex = getViewIndex(getSlotIndex(slot), 0);
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 88d0035..36a0e63 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java
@@ -23,6 +23,7 @@
 
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
+import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.NoCallingIconState;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
 
 /**
@@ -70,6 +71,18 @@
         return holder;
     }
 
+    /**
+     * Creates a new StatusBarIconHolder from a NoCallingIconState.
+     */
+    public static StatusBarIconHolder fromNoCallingState(
+            Context context, NoCallingIconState state) {
+        StatusBarIconHolder holder = new StatusBarIconHolder();
+        holder.mIcon = new StatusBarIcon(UserHandle.SYSTEM, context.getPackageName(),
+                Icon.createWithResource(context, state.resId), 0, 0, null);
+        holder.mTag = state.subId;
+        return holder;
+    }
+
     public int getType() {
         return mType;
     }
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 1fdd816..d11e864 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
@@ -46,6 +46,7 @@
     private final String mSlotWifi;
     private final String mSlotEthernet;
     private final String mSlotVpn;
+    private final String mSlotNoCalling;
 
     private final Context mContext;
     private final StatusBarIconController mIconController;
@@ -66,6 +67,7 @@
     private boolean mWifiVisible = false;
 
     private ArrayList<MobileIconState> mMobileStates = new ArrayList<MobileIconState>();
+    private ArrayList<NoCallingIconState> mNoCallingStates = new ArrayList<NoCallingIconState>();
     private WifiIconState mWifiIconState = new WifiIconState();
 
     public StatusBarSignalPolicy(Context context, StatusBarIconController iconController) {
@@ -76,6 +78,7 @@
         mSlotWifi     = mContext.getString(com.android.internal.R.string.status_bar_wifi);
         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);
         mActivityEnabled = mContext.getResources().getBoolean(R.bool.config_showActivity);
 
         mIconController = iconController;
@@ -198,6 +201,22 @@
     }
 
     @Override
+    public void setNoCallingStatus(boolean noCalling, int subId) {
+        if (DEBUG) {
+            Log.d(TAG, "setNoCallingStatus: "
+                    + "noCalling = " + noCalling + ","
+                    + "subId = " + subId);
+        }
+        NoCallingIconState state = getNoCallingState(subId);
+        if (state == null) {
+            return;
+        }
+        state.visible = noCalling;
+        mIconController.setNoCallingIcons(
+                mSlotNoCalling, NoCallingIconState.copyStates(mNoCallingStates));
+    }
+
+    @Override
     public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
             int qsType, boolean activityIn, boolean activityOut,
             CharSequence typeContentDescription,
@@ -252,6 +271,16 @@
         }
     }
 
+    private NoCallingIconState getNoCallingState(int subId) {
+        for (NoCallingIconState state : mNoCallingStates) {
+            if (state.subId == subId) {
+                return state;
+            }
+        }
+        Log.e(TAG, "Unexpected subscription " + subId);
+        return null;
+    }
+
     private MobileIconState getState(int subId) {
         for (MobileIconState state : mMobileStates) {
             if (state.subId == subId) {
@@ -285,9 +314,11 @@
 
         mIconController.removeAllIconsForSlot(mSlotMobile);
         mMobileStates.clear();
+        mNoCallingStates.clear();
         final int n = subs.size();
         for (int i = 0; i < n; i++) {
             mMobileStates.add(new MobileIconState(subs.get(i).getSubscriptionId()));
+            mNoCallingStates.add(new NoCallingIconState(subs.get(i).getSubscriptionId()));
         }
     }
 
@@ -377,6 +408,53 @@
         // Don't care.
     }
 
+    /**
+     * Stores the StatusBar state for no Calling & SMS.
+     */
+    public static class NoCallingIconState {
+        public boolean visible;
+        public int resId;
+        public int subId;
+
+        private NoCallingIconState(int subId) {
+            this.subId = subId;
+            this.resId = R.drawable.ic_qs_no_calling_sms;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            // Skipping reference equality bc this should be more of a value type
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            NoCallingIconState that = (NoCallingIconState) o;
+            return visible == that.visible
+                    && resId == that.resId
+                    && subId == that.subId;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(visible, resId, subId);
+        }
+
+        private void copyTo(NoCallingIconState other) {
+            other.visible = visible;
+            other.resId = resId;
+            other.subId = subId;
+        }
+
+        private static List<NoCallingIconState> copyStates(List<NoCallingIconState> inStates) {
+            ArrayList<NoCallingIconState> outStates = new ArrayList<>();
+            for (NoCallingIconState state : inStates) {
+                NoCallingIconState copy = new NoCallingIconState(state.subId);
+                state.copyTo(copy);
+                outStates.add(copy);
+            }
+            return outStates;
+        }
+    }
+
     private static abstract class SignalIconState {
         public boolean visible;
         public boolean activityOut;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
index 1cc312a..5e88cd5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
@@ -146,6 +146,15 @@
     }
 
     @Override
+    public void setNoCallingStatus(boolean noCalling, int subId) {
+        post(() -> {
+            for (SignalCallback signalCluster : mSignalCallbacks) {
+                signalCluster.setNoCallingStatus(noCalling, subId);
+            }
+        });
+    }
+
+    @Override
     public void setSubs(List<SubscriptionInfo> subs) {
         obtainMessage(MSG_SUBS_CHANGED, subs).sendToTarget();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyController.java
new file mode 100644
index 0000000..a76d08a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyController.java
@@ -0,0 +1,32 @@
+/*
+ * 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.statusbar.policy;
+
+import android.hardware.SensorPrivacyManager.IndividualSensor;
+
+public interface IndividualSensorPrivacyController extends
+        CallbackController<IndividualSensorPrivacyController.Callback> {
+    void init();
+
+    boolean isSensorBlocked(@IndividualSensor int sensor);
+
+    void setSensorBlocked(@IndividualSensor int sensor, boolean blocked);
+
+    interface Callback {
+        void onSensorBlockedChanged(@IndividualSensor int sensor, boolean blocked);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java
new file mode 100644
index 0000000..231fe08
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java
@@ -0,0 +1,81 @@
+/*
+ * 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.statusbar.policy;
+
+import static android.service.SensorPrivacyIndividualEnabledSensorProto.CAMERA;
+import static android.service.SensorPrivacyIndividualEnabledSensorProto.MICROPHONE;
+
+import android.hardware.SensorPrivacyManager;
+import android.hardware.SensorPrivacyManager.IndividualSensor;
+import android.util.ArraySet;
+import android.util.SparseBooleanArray;
+
+import androidx.annotation.NonNull;
+
+import java.util.Set;
+
+public class IndividualSensorPrivacyControllerImpl implements IndividualSensorPrivacyController {
+
+    private static final int[] SENSORS = new int[] {CAMERA, MICROPHONE};
+
+    private final @NonNull SensorPrivacyManager mSensorPrivacyManager;
+    private final SparseBooleanArray mState = new SparseBooleanArray();
+    private final Set<Callback> mCallbacks = new ArraySet<>();
+
+    public IndividualSensorPrivacyControllerImpl(
+            @NonNull SensorPrivacyManager sensorPrivacyManager) {
+        mSensorPrivacyManager = sensorPrivacyManager;
+    }
+
+    @Override
+    public void init() {
+        for (int sensor : SENSORS) {
+            mSensorPrivacyManager.addSensorPrivacyListener(sensor,
+                    (enabled) -> onSensorPrivacyChanged(sensor, enabled));
+
+            mState.put(sensor, mSensorPrivacyManager.isIndividualSensorPrivacyEnabled(sensor));
+        }
+    }
+
+    @Override
+    public boolean isSensorBlocked(@IndividualSensor int sensor) {
+        return mState.get(sensor, false);
+    }
+
+    @Override
+    public void setSensorBlocked(@IndividualSensor int sensor, boolean blocked) {
+        mSensorPrivacyManager.setIndividualSensorPrivacyForProfileGroup(sensor, blocked);
+    }
+
+    @Override
+    public void addCallback(@NonNull Callback listener) {
+        mCallbacks.add(listener);
+    }
+
+    @Override
+    public void removeCallback(@NonNull Callback listener) {
+        mCallbacks.remove(listener);
+    }
+
+    private void onSensorPrivacyChanged(@IndividualSensor int sensor, boolean blocked) {
+        mState.put(sensor, blocked);
+
+        for (Callback callback : mCallbacks) {
+            callback.onSensorBlockedChanged(sensor, blocked);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 101e3c6..2f66508 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -458,9 +458,24 @@
         mCurrentState.dataSim = mobileStatus.dataSim;
         mCurrentState.carrierNetworkChangeMode = mobileStatus.carrierNetworkChangeMode;
         mDataState = mobileStatus.dataState;
-        mServiceState = mobileStatus.serviceState;
         mSignalStrength = mobileStatus.signalStrength;
         mTelephonyDisplayInfo = mobileStatus.telephonyDisplayInfo;
+        int lastVoiceState = mServiceState != null ? mServiceState.getState() : -1;
+        mServiceState = mobileStatus.serviceState;
+        int currentVoiceState =  mServiceState != null ? mServiceState.getState() : -1;
+        // Only update the no calling Status in the below scenarios
+        // 1. The first valid voice state has been received
+        // 2. The voice state has been changed and either the last or current state is
+        //    ServiceState.STATE_IN_SERVICE
+        if (mProviderModel
+                && lastVoiceState != currentVoiceState
+                && (lastVoiceState == -1
+                        || (lastVoiceState == ServiceState.STATE_IN_SERVICE
+                                || currentVoiceState == ServiceState.STATE_IN_SERVICE))) {
+            notifyNoCallingStatusChange(
+                    currentVoiceState != ServiceState.STATE_IN_SERVICE,
+                    mSubscriptionInfo.getSubscriptionId());
+        }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index a9c6016..f2b0d76 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -92,6 +92,13 @@
          */
         default void setConnectivityStatus(boolean noDefaultNetwork, boolean noValidatedNetwork,
                 boolean noNetworksAvailable) {}
+
+        /**
+         * Callback for listeners to be able to update the no calling & SMS status
+         * @param noCalling whether the calling and SMS is not working.
+         * @param subId subscription ID for which to update the UI
+         */
+        default void setNoCallingStatus(boolean noCalling, int subId) {}
     }
 
     public interface EmergencyListener {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyController.java
index 6d5ce60..4a09234 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyController.java
@@ -23,6 +23,11 @@
         CallbackController<SensorPrivacyController.OnSensorPrivacyChangedListener> {
 
     /**
+     * Initialize the controller. Needs to be called after constructing the object
+     */
+    void init();
+
+    /**
      * Returns whether sensor privacy is enabled.
      */
     boolean isSensorPrivacyEnabled();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyControllerImpl.java
index 20cc46f..a2334f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyControllerImpl.java
@@ -35,20 +35,21 @@
 public class SensorPrivacyControllerImpl implements SensorPrivacyController,
         SensorPrivacyManager.OnSensorPrivacyChangedListener {
     private SensorPrivacyManager mSensorPrivacyManager;
-    private final List<OnSensorPrivacyChangedListener> mListeners;
+    private final List<OnSensorPrivacyChangedListener> mListeners = new ArrayList<>(1);
     private Object mLock = new Object();
     private boolean mSensorPrivacyEnabled;
 
     /**
      * Public constructor.
      */
-    @Inject
-    public SensorPrivacyControllerImpl(Context context) {
-        mSensorPrivacyManager = (SensorPrivacyManager) context.getSystemService(
-                Context.SENSOR_PRIVACY_SERVICE);
+    public SensorPrivacyControllerImpl(@NonNull SensorPrivacyManager sensorPrivacyManager) {
+        mSensorPrivacyManager = sensorPrivacyManager;
+    }
+
+    @Override
+    public void init() {
         mSensorPrivacyEnabled = mSensorPrivacyManager.isSensorPrivacyEnabled();
         mSensorPrivacyManager.addSensorPrivacyListener(this);
-        mListeners = new ArrayList<>(1);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
index a05fe1f..554145e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
@@ -167,6 +167,10 @@
         }
     }
 
+    protected final void notifyNoCallingStatusChange(boolean noCalling, int subId) {
+        mCallbackHandler.setNoCallingStatus(noCalling, subId);
+    }
+
     /**
      * Returns the resource if resId is not 0, and an empty string otherwise.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartRepliesAndActionsInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartRepliesAndActionsInflater.kt
index 6a3a69c..ea80325 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartRepliesAndActionsInflater.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartRepliesAndActionsInflater.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.policy
 
 import android.app.Notification
+import android.app.Notification.Action.SEMANTIC_ACTION_MARK_CONVERSATION_AS_PRIORITY
 import android.app.PendingIntent
 import android.app.RemoteInput
 import android.content.Context
@@ -310,11 +311,19 @@
         actionIndex: Int,
         action: Notification.Action
     ) =
+        if (smartActions.fromAssistant
+            && SEMANTIC_ACTION_MARK_CONVERSATION_AS_PRIORITY == action.semanticAction) {
+            entry.row.doSmartActionClick(entry.row.x.toInt() / 2,
+                entry.row.y.toInt() / 2, SEMANTIC_ACTION_MARK_CONVERSATION_AS_PRIORITY)
+            smartReplyController
+                .smartActionClicked(entry, actionIndex, action, smartActions.fromAssistant)
+        } else {
             activityStarter.startPendingIntentDismissingKeyguard(action.actionIntent, entry.row) {
                 smartReplyController
-                        .smartActionClicked(entry, actionIndex, action, smartActions.fromAssistant)
+                    .smartActionClicked(entry, actionIndex, action, smartActions.fromAssistant)
                 headsUpManager.removeNotification(entry.key, true /* releaseImmediately */)
             }
+        }
 }
 
 interface SmartReplyInflater {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
index 069b405..7a4b912 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
@@ -107,11 +107,6 @@
 
     /** */
     @Binds
-    SensorPrivacyController provideSensorPrivacyControllerImpl(
-            SensorPrivacyControllerImpl controllerImpl);
-
-    /** */
-    @Binds
     UserInfoController provideUserInfoContrller(UserInfoControllerImpl controllerImpl);
 
     /** */
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
index 56a4c203..df889f2 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
@@ -20,6 +20,7 @@
 import static com.android.systemui.Dependency.LEAK_REPORT_EMAIL_NAME;
 
 import android.content.Context;
+import android.hardware.SensorPrivacyManager;
 import android.os.Handler;
 import android.os.PowerManager;
 
@@ -63,6 +64,10 @@
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
+import com.android.systemui.statusbar.policy.IndividualSensorPrivacyControllerImpl;
+import com.android.systemui.statusbar.policy.SensorPrivacyController;
+import com.android.systemui.statusbar.policy.SensorPrivacyControllerImpl;
 import com.android.systemui.statusbar.tv.notifications.TvNotificationHandler;
 
 import javax.inject.Named;
@@ -109,6 +114,25 @@
         return bC;
     }
 
+    @Provides
+    @SysUISingleton
+    static SensorPrivacyController provideSensorPrivacyController(
+            SensorPrivacyManager sensorPrivacyManager) {
+        SensorPrivacyController spC = new SensorPrivacyControllerImpl(sensorPrivacyManager);
+        spC.init();
+        return spC;
+    }
+
+    @Provides
+    @SysUISingleton
+    static IndividualSensorPrivacyController provideIndividualSensorPrivacyController(
+            SensorPrivacyManager sensorPrivacyManager) {
+        IndividualSensorPrivacyController spC = new IndividualSensorPrivacyControllerImpl(
+                sensorPrivacyManager);
+        spC.init();
+        return spC;
+    }
+
     @Binds
     @SysUISingleton
     abstract QSFactory bindQSFactory(QSFactoryImpl qsFactoryImpl);
diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java
index 08cd6e3..8d77c4a 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java
+++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java
@@ -33,7 +33,7 @@
     static final String REASON_WRAP = "wrap";
 
     /**
-     * Default wake-lock timeout, to avoid battery regressions.
+     * Default wake-lock timeout in milliseconds, to avoid battery regressions.
      */
     long DEFAULT_MAX_TIMEOUT = 20000;
 
@@ -104,6 +104,7 @@
                 if (count == null) {
                     Log.wtf(TAG, "Releasing WakeLock with invalid reason: " + why,
                             new Throwable());
+                    return;
                 } else if (count == 1) {
                     mActiveClients.remove(why);
                 } else {
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index 715b0a2..81ac21c 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -55,14 +55,14 @@
 import com.android.systemui.tracing.nano.SystemUiTraceProto;
 import com.android.wm.shell.ShellCommandHandler;
 import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
+import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
 import com.android.wm.shell.nano.WmShellTraceProto;
 import com.android.wm.shell.onehanded.OneHanded;
-import com.android.wm.shell.onehanded.OneHandedEvents;
 import com.android.wm.shell.onehanded.OneHandedGestureHandler.OneHandedGestureEventCallback;
 import com.android.wm.shell.onehanded.OneHandedTransitionCallback;
+import com.android.wm.shell.onehanded.OneHandedUiEventLogger;
 import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.protolog.ShellProtoLogImpl;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -253,7 +253,7 @@
                 mSysUiMainExecutor.execute(() -> {
                     if (oneHanded.isOneHandedEnabled()) {
                         oneHanded.stopOneHanded(
-                                OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_GESTURE_OUT);
+                                OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_GESTURE_OUT);
                     } else if (oneHanded.isSwipeToNotificationEnabled()) {
                         mCommandQueue.handleSystemKey(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP);
                     }
@@ -280,7 +280,7 @@
             @Override
             public void onScreenTurningOff() {
                 oneHanded.stopOneHanded(
-                        OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_SCREEN_OFF_OUT);
+                        OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_SCREEN_OFF_OUT);
             }
         });
 
@@ -294,7 +294,8 @@
             public void setImeWindowStatus(int displayId, IBinder token, int vis,
                     int backDisposition, boolean showImeSwitcher) {
                 if (displayId == DEFAULT_DISPLAY && (vis & InputMethodService.IME_VISIBLE) != 0) {
-                    oneHanded.stopOneHanded(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_POP_IME_OUT);
+                    oneHanded.stopOneHanded(
+                            OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_POP_IME_OUT);
                 }
             }
         });
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index 1b5877f..bbc238a 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -350,10 +350,11 @@
     @Provides
     static Optional<OneHanded> provideOneHandedController(Context context,
             DisplayController displayController, TaskStackListenerImpl taskStackListener,
+            UiEventLogger uiEventLogger,
             @ShellMainThread ShellExecutor mainExecutor,
             @ShellMainThread Handler mainHandler) {
         return Optional.ofNullable(OneHandedController.create(context, displayController,
-                taskStackListener, mainExecutor, mainHandler));
+                taskStackListener, uiEventLogger, mainExecutor, mainHandler));
     }
 
     @WMSingleton
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 b24f4ab..c052563 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -106,6 +106,7 @@
     @Captor private ArgumentCaptor<IUdfpsOverlayController> mOverlayCaptor;
     private IUdfpsOverlayController mOverlayController;
     @Captor private ArgumentCaptor<UdfpsView.OnTouchListener> mTouchListenerCaptor;
+    @Captor private ArgumentCaptor<Runnable> mRunAfterShowingScrimAndDotCaptor;
 
     @Before
     public void setUp() {
@@ -190,11 +191,14 @@
         MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
         event.recycle();
-        // THEN the event is passed to the FingerprintManager
+        // THEN the scrim and dot is shown
+        verify(mUdfpsView).showScrimAndDot();
+        // AND a runnable that passes the event to FingerprintManager is set on the view
+        verify(mUdfpsView).setRunAfterShowingScrimAndDot(
+                mRunAfterShowingScrimAndDotCaptor.capture());
+        mRunAfterShowingScrimAndDotCaptor.getValue().run();
         verify(mFingerprintManager).onPointerDown(eq(mUdfpsController.mSensorProps.sensorId), eq(0),
                 eq(0), eq(0f), eq(0f));
-        // AND the scrim and dot is shown
-        verify(mUdfpsView).showScrimAndDot();
     }
 
     @Test
@@ -205,11 +209,14 @@
         mFgExecutor.runAllReady();
         // WHEN fingerprint is requested because of AOD interrupt
         mUdfpsController.onAodInterrupt(0, 0, 2f, 3f);
-        // THEN the event is passed to the FingerprintManager
+        // THEN the scrim and dot is shown
+        verify(mUdfpsView).showScrimAndDot();
+        // AND a runnable that passes the event to FingerprintManager is set on the view
+        verify(mUdfpsView).setRunAfterShowingScrimAndDot(
+                mRunAfterShowingScrimAndDotCaptor.capture());
+        mRunAfterShowingScrimAndDotCaptor.getValue().run();
         verify(mFingerprintManager).onPointerDown(eq(mUdfpsController.mSensorProps.sensorId), eq(0),
                 eq(0), eq(3f) /* minor */, eq(2f) /* major */);
-        // AND the scrim and dot is shown
-        verify(mUdfpsView).showScrimAndDot();
     }
 
     @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
index 4d32a3b..b63274b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java
@@ -42,6 +42,7 @@
 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.transition.Transitions;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -75,6 +76,7 @@
     @Mock private Optional<com.android.wm.shell.onehanded.OneHanded> mMockOneHandedOptional;
     @Mock private PackageManager mPackageManager;
     @Mock private SysUiState mMockSysUiState;
+    @Mock private Transitions mMockTransitions;
 
     @Before
     public void setUp() throws RemoteException {
@@ -89,7 +91,7 @@
                 mMockNavBarControllerLazy, mMockNavModeController, mMockStatusBarWinController,
                 mMockSysUiState, mMockPipOptional, mMockSplitScreenOptional,
                 mMockStatusBarOptionalLazy, mMockOneHandedOptional,
-                mMockBroadcastDispatcher));
+                mMockBroadcastDispatcher, mMockTransitions));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java
index ced8428..03f93fa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java
@@ -43,7 +43,7 @@
 
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ShareTransition;
+import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ActionTransition;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -177,10 +177,10 @@
         data.mActionsReadyListener = null;
         SaveImageInBackgroundTask task =
                 new SaveImageInBackgroundTask(mContext, null, mScreenshotSmartActions, data,
-                        ShareTransition::new);
+                        ActionTransition::new);
 
         Notification.Action shareAction = task.createShareAction(mContext, mContext.getResources(),
-                Uri.parse("Screenshot_123.png")).get().shareAction;
+                Uri.parse("Screenshot_123.png")).get().action;
 
         Intent intent = shareAction.actionIntent.getIntent();
         assertNotNull(intent);
@@ -205,10 +205,10 @@
         data.mActionsReadyListener = null;
         SaveImageInBackgroundTask task =
                 new SaveImageInBackgroundTask(mContext, null, mScreenshotSmartActions, data,
-                        ShareTransition::new);
+                        ActionTransition::new);
 
         Notification.Action editAction = task.createEditAction(mContext, mContext.getResources(),
-                Uri.parse("Screenshot_123.png"));
+                Uri.parse("Screenshot_123.png")).get().action;
 
         Intent intent = editAction.actionIntent.getIntent();
         assertNotNull(intent);
@@ -233,7 +233,7 @@
         data.mActionsReadyListener = null;
         SaveImageInBackgroundTask task =
                 new SaveImageInBackgroundTask(mContext, null, mScreenshotSmartActions, data,
-                        ShareTransition::new);
+                        ActionTransition::new);
 
         Notification.Action deleteAction = task.createDeleteAction(mContext,
                 mContext.getResources(),
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 d2d5708..2917dfa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -17,6 +17,7 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
 import static android.view.InsetsState.ITYPE_STATUS_BAR;
+import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT;
 
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Matchers.eq;
@@ -30,6 +31,7 @@
 import android.hardware.biometrics.PromptInfo;
 import android.os.Bundle;
 import android.view.WindowInsetsController.Appearance;
+import android.view.WindowInsetsController.Behavior;
 
 import androidx.test.filters.SmallTest;
 
@@ -116,24 +118,27 @@
     }
 
     @Test
-    public void testOnSystemBarAppearanceChanged() {
-        doTestOnSystemBarAppearanceChanged(DEFAULT_DISPLAY, 1,
-                new AppearanceRegion[]{new AppearanceRegion(2, new Rect())}, false);
+    public void testOnSystemBarAttributesChanged() {
+        doTestOnSystemBarAttributesChanged(DEFAULT_DISPLAY, 1,
+                new AppearanceRegion[]{new AppearanceRegion(2, new Rect())}, false,
+                BEHAVIOR_DEFAULT, false);
     }
 
     @Test
-    public void testOnSystemBarAppearanceChangedForSecondaryDisplay() {
-        doTestOnSystemBarAppearanceChanged(SECONDARY_DISPLAY, 1,
-                new AppearanceRegion[]{new AppearanceRegion(2, new Rect())}, false);
+    public void testOnSystemBarAttributesChangedForSecondaryDisplay() {
+        doTestOnSystemBarAttributesChanged(SECONDARY_DISPLAY, 1,
+                new AppearanceRegion[]{new AppearanceRegion(2, new Rect())}, false,
+                BEHAVIOR_DEFAULT, false);
     }
 
-    private void doTestOnSystemBarAppearanceChanged(int displayId, @Appearance int appearance,
-            AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme) {
-        mCommandQueue.onSystemBarAppearanceChanged(displayId, appearance, appearanceRegions,
-                navbarColorManagedByIme);
+    private void doTestOnSystemBarAttributesChanged(int displayId, @Appearance int appearance,
+            AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
+            @Behavior int behavior, boolean isFullscreen) {
+        mCommandQueue.onSystemBarAttributesChanged(displayId, appearance, appearanceRegions,
+                navbarColorManagedByIme, behavior, isFullscreen);
         waitForIdleSync();
-        verify(mCallbacks).onSystemBarAppearanceChanged(eq(displayId), eq(appearance),
-                eq(appearanceRegions), eq(navbarColorManagedByIme));
+        verify(mCallbacks).onSystemBarAttributesChanged(eq(displayId), eq(appearance),
+                eq(appearanceRegions), eq(navbarColorManagedByIme), eq(behavior), eq(isFullscreen));
     }
 
     @Test
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 291b223..5c37656 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
@@ -241,6 +241,7 @@
     @Test
     public void testBindNotification_SetsShortcutIcon() {
         mNotificationInfo.bindNotification(
+                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mMockINotificationManager,
@@ -265,6 +266,7 @@
     public void testBindNotification_SetsTextApplicationName() {
         when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
         mNotificationInfo.bindNotification(
+                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mMockINotificationManager,
@@ -289,6 +291,7 @@
     @Test
     public void testBindNotification_SetsTextChannelName() {
         mNotificationInfo.bindNotification(
+                -1,
                 mShortcutManager,
                 mLauncherApps,
                 mMockPackageManager,
@@ -316,6 +319,7 @@
         mConversationChannel.setGroup(group.getId());
 
         mNotificationInfo.bindNotification(
+                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mMockINotificationManager,
@@ -341,6 +345,7 @@
     @Test
     public void testBindNotification_GroupNameHiddenIfNoGroup() {
         mNotificationInfo.bindNotification(
+                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mMockINotificationManager,
@@ -365,6 +370,7 @@
     @Test
     public void testBindNotification_noDelegate() {
         mNotificationInfo.bindNotification(
+                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mMockINotificationManager,
@@ -400,6 +406,7 @@
                 .setShortcutInfo(mShortcutInfo)
                 .build();
         mNotificationInfo.bindNotification(
+                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mMockINotificationManager,
@@ -425,6 +432,7 @@
     public void testBindNotification_SetsOnClickListenerForSettings() {
         final CountDownLatch latch = new CountDownLatch(1);
         mNotificationInfo.bindNotification(
+                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mMockINotificationManager,
@@ -454,6 +462,7 @@
     @Test
     public void testBindNotification_SettingsButtonInvisibleWhenNoClickListener() {
         mNotificationInfo.bindNotification(
+                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mMockINotificationManager,
@@ -478,6 +487,7 @@
     public void testBindNotification_SettingsButtonInvisibleWhenDeviceUnprovisioned() {
         final CountDownLatch latch = new CountDownLatch(1);
         mNotificationInfo.bindNotification(
+                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mMockINotificationManager,
@@ -506,6 +516,7 @@
         mConversationChannel.setImportance(IMPORTANCE_LOW);
         mConversationChannel.setImportantConversation(true);
         mNotificationInfo.bindNotification(
+                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mMockINotificationManager,
@@ -534,6 +545,7 @@
         mConversationChannel.setImportantConversation(false);
         mConversationChannel.setAllowBubbles(true);
         mNotificationInfo.bindNotification(
+                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mMockINotificationManager,
@@ -565,6 +577,7 @@
         mConversationChannel.setImportantConversation(false);
         mConversationChannel.setAllowBubbles(true);
         mNotificationInfo.bindNotification(
+                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mMockINotificationManager,
@@ -595,6 +608,7 @@
         mConversationChannel.setImportantConversation(false);
 
         mNotificationInfo.bindNotification(
+                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mMockINotificationManager,
@@ -639,6 +653,7 @@
         mConversationChannel.setImportance(IMPORTANCE_LOW);
         mConversationChannel.setImportantConversation(false);
         mNotificationInfo.bindNotification(
+                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mMockINotificationManager,
@@ -682,6 +697,7 @@
         mConversationChannel.setImportantConversation(false);
 
         mNotificationInfo.bindNotification(
+                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mMockINotificationManager,
@@ -726,6 +742,7 @@
         mConversationChannel.setImportantConversation(false);
 
         mNotificationInfo.bindNotification(
+                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mMockINotificationManager,
@@ -763,6 +780,7 @@
         mConversationChannel.setImportance(9);
 
         mNotificationInfo.bindNotification(
+                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mMockINotificationManager,
@@ -799,6 +817,7 @@
         mConversationChannel.setImportantConversation(true);
 
         mNotificationInfo.bindNotification(
+                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mMockINotificationManager,
@@ -832,11 +851,75 @@
     }
 
     @Test
+    public void testDefaultSelectedWhenChannelIsDefault() throws Exception {
+        // GIVEN channel importance indicates "Default" priority
+        mConversationChannel.setImportance(IMPORTANCE_HIGH);
+        mConversationChannel.setImportantConversation(false);
+
+        // WHEN we indicate no selected action
+        mNotificationInfo.bindNotification(
+                -1, // no action selected by default
+                mShortcutManager,
+                mMockPackageManager,
+                mMockINotificationManager,
+                mOnUserInteractionCallback,
+                TEST_PACKAGE_NAME,
+                mNotificationChannel,
+                mEntry,
+                mBubbleMetadata,
+                null,
+                null,
+                mIconFactory,
+                mContext,
+                mBuilderProvider,
+                true,
+                mTestHandler,
+                mTestHandler, null, Optional.of(mBubblesManager));
+
+        // THEN the selected action is -1, so the selected option is "Default" priority
+        assertEquals(mNotificationInfo.getSelectedAction(), -1);
+        assertTrue(mNotificationInfo.findViewById(R.id.default_behavior).isSelected());
+    }
+
+    @Test
+    public void testFavoriteSelectedWhenChannelIsDefault() throws Exception {
+        // GIVEN channel importance indicates "Default" priority
+        mConversationChannel.setImportance(IMPORTANCE_HIGH);
+        mConversationChannel.setImportantConversation(false);
+
+        // WHEN we indicate the selected action should be "Favorite"
+        mNotificationInfo.bindNotification(
+                NotificationConversationInfo.ACTION_FAVORITE, // "Favorite" selected by default
+                mShortcutManager,
+                mMockPackageManager,
+                mMockINotificationManager,
+                mOnUserInteractionCallback,
+                TEST_PACKAGE_NAME,
+                mNotificationChannel,
+                mEntry,
+                mBubbleMetadata,
+                null,
+                null,
+                mIconFactory,
+                mContext,
+                mBuilderProvider,
+                true,
+                mTestHandler,
+                mTestHandler, null, Optional.of(mBubblesManager));
+
+        // THEN the selected action is "Favorite", so the selected option is "priority" priority
+        assertEquals(mNotificationInfo.getSelectedAction(),
+                NotificationConversationInfo.ACTION_FAVORITE);
+        assertTrue(mNotificationInfo.findViewById(R.id.priority).isSelected());
+    }
+
+    @Test
     public void testDefault_andSave() throws Exception {
         mConversationChannel.setAllowBubbles(true);
         mConversationChannel.setOriginalImportance(IMPORTANCE_HIGH);
         mConversationChannel.setImportantConversation(true);
         mNotificationInfo.bindNotification(
+                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mMockINotificationManager,
@@ -873,6 +956,7 @@
         mConversationChannel.setOriginalImportance(IMPORTANCE_HIGH);
         mConversationChannel.setImportantConversation(false);
         mNotificationInfo.bindNotification(
+                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mMockINotificationManager,
@@ -909,6 +993,7 @@
         mConversationChannel.setOriginalImportance(IMPORTANCE_HIGH);
 
         mNotificationInfo.bindNotification(
+                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mMockINotificationManager,
@@ -944,6 +1029,7 @@
         mConversationChannel.setAllowBubbles(true);
 
         mNotificationInfo.bindNotification(
+                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mMockINotificationManager,
@@ -978,6 +1064,7 @@
     @Test
     public void testBindNotification_createsNewChannel() throws Exception {
         mNotificationInfo.bindNotification(
+                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mMockINotificationManager,
@@ -1003,6 +1090,7 @@
     public void testBindNotification_doesNotCreateNewChannelIfExists() throws Exception {
         mNotificationChannel.setConversationId("", CONVERSATION_ID);
         mNotificationInfo.bindNotification(
+                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mMockINotificationManager,
@@ -1038,6 +1126,7 @@
 
         // GIVEN the user is changing conversation settings
         mNotificationInfo.bindNotification(
+                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mMockINotificationManager,
@@ -1078,6 +1167,7 @@
         when(b.build()).thenReturn(controller);
 
         mNotificationInfo.bindNotification(
+                -1,
                 mShortcutManager,
                 mMockPackageManager,
                 mMockINotificationManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
index dbb4512..cdfab1e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
@@ -18,6 +18,7 @@
 
 import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
 import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
+import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT;
 
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
@@ -95,21 +96,25 @@
 
     @Test
     public void testAreLightsOut_lightsOut() {
-        mCallbacks.onSystemBarAppearanceChanged(
+        mCallbacks.onSystemBarAttributesChanged(
                 mDisplayId /* display id */,
                 LIGHTS_OUT /* appearance */,
                 null /* appearanceRegions */,
-                false /* navbarColorManagedByIme */);
+                false /* navbarColorManagedByIme */,
+                BEHAVIOR_DEFAULT,
+                false /* isFullscreen */);
         assertTrue(mLightsOutNotifController.areLightsOut());
     }
 
     @Test
     public void testAreLightsOut_lightsOn() {
-        mCallbacks.onSystemBarAppearanceChanged(
+        mCallbacks.onSystemBarAttributesChanged(
                 mDisplayId /* display id */,
                 LIGHTS_ON /* appearance */,
                 null /* appearanceRegions */,
-                false /* navbarColorManagedByIme */);
+                false /* navbarColorManagedByIme */,
+                BEHAVIOR_DEFAULT,
+                false /* isFullscreen */);
         assertFalse(mLightsOutNotifController.areLightsOut());
     }
 
@@ -128,16 +133,18 @@
     }
 
     @Test
-    public void testLightsOut_withNotifs_onSystemBarAppearanceChanged() {
+    public void testLightsOut_withNotifs_onSystemBarAttributesChanged() {
         // GIVEN active visible notifications
         when(mEntryManager.hasActiveNotifications()).thenReturn(true);
 
         // WHEN lights out
-        mCallbacks.onSystemBarAppearanceChanged(
+        mCallbacks.onSystemBarAttributesChanged(
                 mDisplayId /* display id */,
                 LIGHTS_OUT /* appearance */,
                 null /* appearanceRegions */,
-                false /* navbarColorManagedByIme */);
+                false /* navbarColorManagedByIme */,
+                BEHAVIOR_DEFAULT,
+                false /* isFullscreen */);
 
         // THEN we should show dot
         assertTrue(mLightsOutNotifController.shouldShowDot());
@@ -145,16 +152,18 @@
     }
 
     @Test
-    public void testLightsOut_withoutNotifs_onSystemBarAppearanceChanged() {
+    public void testLightsOut_withoutNotifs_onSystemBarAttributesChanged() {
         // GIVEN no active visible notifications
         when(mEntryManager.hasActiveNotifications()).thenReturn(false);
 
         // WHEN lights out
-        mCallbacks.onSystemBarAppearanceChanged(
+        mCallbacks.onSystemBarAttributesChanged(
                 mDisplayId /* display id */,
                 LIGHTS_OUT /* appearance */,
                 null /* appearanceRegions */,
-                false /* navbarColorManagedByIme */);
+                false /* navbarColorManagedByIme */,
+                BEHAVIOR_DEFAULT,
+                false /* isFullscreen */);
 
         // THEN we shouldn't show the dot
         assertFalse(mLightsOutNotifController.shouldShowDot());
@@ -162,16 +171,18 @@
     }
 
     @Test
-    public void testLightsOn_afterLightsOut_onSystemBarAppearanceChanged() {
+    public void testLightsOn_afterLightsOut_onSystemBarAttributesChanged() {
         // GIVEN active visible notifications
         when(mEntryManager.hasActiveNotifications()).thenReturn(true);
 
         // WHEN lights on
-        mCallbacks.onSystemBarAppearanceChanged(
+        mCallbacks.onSystemBarAttributesChanged(
                 mDisplayId /* display id */,
                 LIGHTS_ON /* appearance */,
                 null /* appearanceRegions */,
-                false /* navbarColorManagedByIme */);
+                false /* navbarColorManagedByIme */,
+                BEHAVIOR_DEFAULT,
+                false /* isFullscreen */);
 
         // THEN we shouldn't show the dot
         assertFalse(mLightsOutNotifController.shouldShowDot());
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 8e84f1a..51ce8e5 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
@@ -24,7 +24,6 @@
 import static junit.framework.Assert.assertTrue;
 import static junit.framework.TestCase.fail;
 
-import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -35,7 +34,6 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -45,7 +43,6 @@
 import android.app.trust.TrustManager;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
-import android.content.Intent;
 import android.content.IntentFilter;
 import android.hardware.display.AmbientDisplayConfiguration;
 import android.hardware.fingerprint.FingerprintManager;
@@ -87,7 +84,6 @@
 import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.demomode.DemoModeController;
-import com.android.systemui.emergency.EmergencyGesture;
 import com.android.systemui.keyguard.DismissCallbackRegistry;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.ScreenLifecycle;
@@ -151,10 +147,8 @@
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -887,19 +881,6 @@
         verify(mDozeServiceHost).setDozeSuppressed(false);
     }
 
-    @Ignore // TODO (b/175240607) - Figure out if the device will actually dial 911.
-    @Test
-    public void onEmergencyActionLaunchGesture_launchesEmergencyIntent() {
-        ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
-        StatusBar statusBarSpy = spy(mStatusBar);
-
-        statusBarSpy.onEmergencyActionLaunchGestureDetected();
-
-        verify(statusBarSpy).startActivity(intentCaptor.capture(), eq(true));
-        Intent sentIntent = intentCaptor.getValue();
-        assertEquals(sentIntent.getAction(), EmergencyGesture.ACTION_LAUNCH_EMERGENCY);
-    }
-
     public static class TestableNotificationInterruptStateProviderImpl extends
             NotificationInterruptStateProviderImpl {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java
index 3357be8..fe01f84 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java
@@ -19,6 +19,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import android.os.Build;
 import android.os.PowerManager;
 
 import androidx.test.filters.SmallTest;
@@ -85,4 +86,14 @@
         assertTrue(ran[0]);
         assertFalse(mInner.isHeld());
     }
+
+    @Test
+    public void prodBuild_wakeLock_releaseWithoutAcquire_noThrow() {
+        if (Build.IS_ENG) {
+            return;
+        }
+
+        // shouldn't throw an exception on production builds
+        mWakeLock.release(WHY);
+    }
 }
\ No newline at end of file
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 2e874a6..c0af15b 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
@@ -20,6 +20,7 @@
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
+import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.NoCallingIconState;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
 
 import java.util.List;
@@ -65,6 +66,10 @@
     }
 
     @Override
+    public void setNoCallingIcons(String slot, List<NoCallingIconState> states) {
+    }
+
+    @Override
     public void setIconVisibility(String slotTty, boolean b) {
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
index 446d3f2..8b86403 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
@@ -120,4 +120,4 @@
         verify(mConfigurationController).addCallback(
                 any(ConfigurationController.ConfigurationListener.class));
     }
-}
\ No newline at end of file
+}
diff --git a/packages/services/CameraExtensionsProxy/OWNERS b/packages/services/CameraExtensionsProxy/OWNERS
new file mode 100644
index 0000000..f48a95c
--- /dev/null
+++ b/packages/services/CameraExtensionsProxy/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/av:/camera/OWNERS
diff --git a/services/accessibility/OWNERS b/services/accessibility/OWNERS
index c6f42f7..a31cfae 100644
--- a/services/accessibility/OWNERS
+++ b/services/accessibility/OWNERS
@@ -1,4 +1,4 @@
 svetoslavganov@google.com
 pweaver@google.com
 rhedjao@google.com
-qasid@google.com
+ryanlwlin@google.com
diff --git a/services/core/java/android/power/PowerStatsInternal.java b/services/core/java/android/power/PowerStatsInternal.java
new file mode 100644
index 0000000..9c908c3
--- /dev/null
+++ b/services/core/java/android/power/PowerStatsInternal.java
@@ -0,0 +1,42 @@
+/*
+ * 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.power;
+
+import android.hardware.power.stats.EnergyConsumerId;
+import android.hardware.power.stats.EnergyConsumerResult;
+
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Power stats local system service interface.
+ *
+ * @hide Only for use within Android OS.
+ */
+public abstract class PowerStatsInternal {
+    /**
+     * Returns a CompletableFuture that will get an {@link EnergyConsumerResult} array for the
+     * available requested energy consumers (power models).
+     *
+     * @param energyConsumerIds Array of {@link EnergyConsumerId} for which energy consumed is being
+     *                          requested.
+     *
+     * @return A Future containing a list of {@link EnergyConsumerResult} objects containing energy
+     *         consumer results for all listed {@link EnergyConsumerId}.
+     */
+    public abstract CompletableFuture<EnergyConsumerResult[]> getEnergyConsumedAsync(
+            @EnergyConsumerId int[] energyConsumerIds);
+}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 6b45abd..7541833 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -194,7 +194,6 @@
 import com.android.server.connectivity.DataConnectionStats;
 import com.android.server.connectivity.DnsManager;
 import com.android.server.connectivity.DnsManager.PrivateDnsValidationUpdate;
-import com.android.server.connectivity.IpConnectivityMetrics;
 import com.android.server.connectivity.KeepaliveTracker;
 import com.android.server.connectivity.LingerMonitor;
 import com.android.server.connectivity.MockableSystemProperties;
@@ -889,6 +888,13 @@
         }
 
         /**
+         * Get a reference to the system keystore.
+         */
+        public KeyStore getKeyStore() {
+            return KeyStore.getInstance();
+        }
+
+        /**
          * @see ProxyTracker
          */
         public ProxyTracker makeProxyTracker(@NonNull Context context,
@@ -918,14 +924,6 @@
             return new MultinetworkPolicyTracker(c, h, r);
         }
 
-        /**
-         * @see IpConnectivityMetrics.Logger
-         */
-        public IpConnectivityMetrics.Logger getMetricsLogger() {
-            return Objects.requireNonNull(LocalServices.getService(IpConnectivityMetrics.Logger.class),
-                    "no IpConnectivityMetrics service");
-        }
-
         public IBatteryStats getBatteryStatsService() {
             return BatteryStatsService.getService();
         }
@@ -990,7 +988,7 @@
         mProxyTracker = mDeps.makeProxyTracker(mContext, mHandler);
 
         mNetd = netd;
-        mKeyStore = KeyStore.getInstance();
+        mKeyStore = mDeps.getKeyStore();
         mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
         mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
         mLocationPermissionChecker = new LocationPermissionChecker(mContext);
@@ -1653,7 +1651,6 @@
     private NetworkCapabilities getNetworkCapabilitiesInternal(NetworkAgentInfo nai) {
         if (nai == null) return null;
         synchronized (nai) {
-            if (nai.networkCapabilities == null) return null;
             return networkCapabilitiesRestrictedForCallerPermissions(
                     nai.networkCapabilities, Binder.getCallingPid(), mDeps.getCallingUid());
         }
@@ -2777,7 +2774,6 @@
     }
 
     private boolean isLiveNetworkAgent(NetworkAgentInfo nai, int what) {
-        if (nai.network == null) return false;
         final NetworkAgentInfo officialNai = getNetworkAgentInfoForNetwork(nai.network);
         if (officialNai != null && officialNai.equals(nai)) return true;
         if (officialNai != null || VDBG) {
@@ -3470,6 +3466,7 @@
             // available until we've told netd to delete it below.
             mNetworkForNetId.remove(nai.network.getNetId());
         }
+        propagateUnderlyingNetworkCapabilities(nai.network);
         // Remove all previously satisfied requests.
         for (int i = 0; i < nai.numNetworkRequests(); i++) {
             NetworkRequest request = nai.requestAt(i);
@@ -3482,7 +3479,9 @@
             }
         }
         nai.clearLingerState();
-        propagateUnderlyingNetworkCapabilities(nai.network);
+        // TODO: this loop, and the mLegacyTypeTracker.remove just below it, seem redundant given
+        // there's a full rematch right after. Currently, deleting it breaks tests that check for
+        // the default network disconnecting. Find out why, fix the rematch code, and delete this.
         if (nai.isSatisfyingRequest(mDefaultRequest.requestId)) {
             mDefaultNetworkNai = null;
             updateDataActivityTracking(null /* newNetwork */, nai);
@@ -4993,16 +4992,23 @@
         mVpnBlockedUidRanges = newVpnBlockedUidRanges;
     }
 
+    private boolean isLockdownVpnEnabled() {
+        return mKeyStore.contains(Credentials.LOCKDOWN_VPN);
+    }
+
     @Override
     public boolean updateLockdownVpn() {
-        if (mDeps.getCallingUid() != Process.SYSTEM_UID) {
-            logw("Lockdown VPN only available to AID_SYSTEM");
+        // Allow the system UID for the system server and for Settings.
+        // Also, for unit tests, allow the process that ConnectivityService is running in.
+        if (mDeps.getCallingUid() != Process.SYSTEM_UID
+                && Binder.getCallingPid() != Process.myPid()) {
+            logw("Lockdown VPN only available to system process or AID_SYSTEM");
             return false;
         }
 
         synchronized (mVpns) {
             // Tear down existing lockdown if profile was removed
-            mLockdownEnabled = LockdownVpnTracker.isEnabled();
+            mLockdownEnabled = isLockdownVpnEnabled();
             if (mLockdownEnabled) {
                 byte[] profileTag = mKeyStore.get(Credentials.LOCKDOWN_VPN);
                 if (profileTag == null) {
@@ -5023,7 +5029,8 @@
                     logw("VPN for user " + user + " not ready yet. Skipping lockdown");
                     return false;
                 }
-                setLockdownTracker(new LockdownVpnTracker(mContext, this, mHandler, vpn, profile));
+                setLockdownTracker(
+                        new LockdownVpnTracker(mContext, this, mHandler, mKeyStore, vpn,  profile));
             } else {
                 setLockdownTracker(null);
             }
@@ -5111,7 +5118,7 @@
 
         synchronized (mVpns) {
             // Can't set always-on VPN if legacy VPN is already in lockdown mode.
-            if (LockdownVpnTracker.isEnabled()) {
+            if (isLockdownVpnEnabled()) {
                 return false;
             }
 
@@ -5217,7 +5224,7 @@
             }
             userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, mNetd, userId, mKeyStore);
             mVpns.put(userId, userVpn);
-            if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) {
+            if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) {
                 updateLockdownVpn();
             }
         }
@@ -5301,7 +5308,7 @@
     private void onUserUnlocked(int userId) {
         synchronized (mVpns) {
             // User present may be sent because of an unlock, which might mean an unlocked keystore.
-            if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) {
+            if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) {
                 updateLockdownVpn();
             } else {
                 startAlwaysOnVpn(userId);
@@ -6068,6 +6075,10 @@
     public Network registerNetworkAgent(INetworkAgent na, NetworkInfo networkInfo,
             LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
             int currentScore, NetworkAgentConfig networkAgentConfig, int providerId) {
+        Objects.requireNonNull(networkInfo, "networkInfo must not be null");
+        Objects.requireNonNull(linkProperties, "linkProperties must not be null");
+        Objects.requireNonNull(networkCapabilities, "networkCapabilities must not be null");
+        Objects.requireNonNull(networkAgentConfig, "networkAgentConfig must not be null");
         if (networkCapabilities.hasTransport(TRANSPORT_TEST)) {
             enforceAnyPermissionOf(Manifest.permission.MANAGE_TEST_NETWORKS);
         } else {
@@ -6606,7 +6617,7 @@
         }
 
         // Don't modify caller's NetworkCapabilities.
-        NetworkCapabilities newNc = new NetworkCapabilities(nc);
+        final NetworkCapabilities newNc = new NetworkCapabilities(nc);
         if (nai.lastValidated) {
             newNc.addCapability(NET_CAPABILITY_VALIDATED);
         } else {
@@ -6694,26 +6705,21 @@
             notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
         }
 
-        // TODO : static analysis indicates that prevNc can't be null here (getAndSetNetworkCaps
-        // never returns null), so mark the relevant members and functions in nai as @NonNull and
-        // remove this test
-        if (prevNc != null) {
-            final boolean oldMetered = prevNc.isMetered();
-            final boolean newMetered = newNc.isMetered();
-            final boolean meteredChanged = oldMetered != newMetered;
+        final boolean oldMetered = prevNc.isMetered();
+        final boolean newMetered = newNc.isMetered();
+        final boolean meteredChanged = oldMetered != newMetered;
 
-            if (meteredChanged) {
-                maybeNotifyNetworkBlocked(nai, oldMetered, newMetered, mRestrictBackground,
-                        mRestrictBackground, mVpnBlockedUidRanges, mVpnBlockedUidRanges);
-            }
+        if (meteredChanged) {
+            maybeNotifyNetworkBlocked(nai, oldMetered, newMetered, mRestrictBackground,
+                    mRestrictBackground, mVpnBlockedUidRanges, mVpnBlockedUidRanges);
+        }
 
-            final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING) !=
-                    newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
+        final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING)
+                != newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
 
-            // Report changes that are interesting for network statistics tracking.
-            if (meteredChanged || roamingChanged) {
-                notifyIfacesChangedForNetworkStats();
-            }
+        // Report changes that are interesting for network statistics tracking.
+        if (meteredChanged || roamingChanged) {
+            notifyIfacesChangedForNetworkStats();
         }
 
         // This network might have been underlying another network. Propagate its capabilities.
@@ -7588,10 +7594,6 @@
         if (!networkAgent.everConnected && state == NetworkInfo.State.CONNECTED) {
             networkAgent.everConnected = true;
 
-            if (networkAgent.linkProperties == null) {
-                Log.wtf(TAG, networkAgent.toShortString() + " connected with null LinkProperties");
-            }
-
             // NetworkCapabilities need to be set before sending the private DNS config to
             // NetworkMonitor, otherwise NetworkMonitor cannot determine if validation is required.
             networkAgent.getAndSetNetworkCapabilities(networkAgent.networkCapabilities);
diff --git a/services/core/java/com/android/server/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java
index a6d9bf8..f04af8b 100644
--- a/services/core/java/com/android/server/DropBoxManagerService.java
+++ b/services/core/java/com/android/server/DropBoxManagerService.java
@@ -73,7 +73,6 @@
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.SortedSet;
@@ -446,7 +445,10 @@
             // from an in-memory buffer, or another file on disk; if we buffered
             // we'd lose out on sendfile() optimizations
             if (forceCompress) {
-                FileUtils.copy(in, new GZIPOutputStream(new FileOutputStream(fd)));
+                final GZIPOutputStream gzipOutputStream =
+                        new GZIPOutputStream(new FileOutputStream(fd));
+                FileUtils.copy(in, gzipOutputStream);
+                gzipOutputStream.finish();
             } else {
                 FileUtils.copy(in, new FileOutputStream(fd));
             }
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index dfcc325..b14ce1c 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -5,7 +5,7 @@
 per-file VibratorManagerService.java, VibratorService.java, DisplayThread.java = michaelwr@google.com, ogunwale@google.com
 
 # Zram writeback
-per-file ZramWriteback.java = minchan@google.com, rajekumar@google.com, srnvs@google.com
+per-file ZramWriteback.java = minchan@google.com, rajekumar@google.com
 
 # Userspace reboot
 per-file UserspaceRebootLogger.java = ioffe@google.com, tomcherry@google.com
@@ -30,6 +30,7 @@
 per-file MmsServiceBroker.java = file:/telephony/OWNERS
 per-file NetIdManager.java = file:/services/core/java/com/android/server/net/OWNERS
 per-file PackageWatchdog.java = file:/services/core/java/com/android/server/rollback/OWNERS
+per-file PinnerService.java = file:/apct-tests/perftests/OWNERS
 per-file TelephonyRegistry.java = file:/telephony/OWNERS
 per-file UiModeManagerService.java = file:/packages/SystemUI/OWNERS
 per-file VcnManagementService.java = file:/services/core/java/com/android/server/vcn/OWNERS
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index a3bcbbe..871de0d 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -43,6 +43,8 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -61,7 +63,6 @@
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.function.pooled.PooledLambda;
-import com.android.server.SystemService.TargetUser;
 import com.android.server.wm.ActivityTaskManagerInternal;
 
 import dalvik.system.DexFile;
@@ -70,6 +71,7 @@
 import java.io.Closeable;
 import java.io.DataInputStream;
 import java.io.FileDescriptor;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintWriter;
@@ -100,12 +102,6 @@
     private static final int KEY_HOME = 1;
     private static final int KEY_ASSISTANT = 2;
 
-    // Pin the camera application. Default to the system property only if the experiment phenotype
-    // property is not set.
-    private static boolean PROP_PIN_CAMERA =
-            DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT,
-                                    "pin_camera",
-                                    SystemProperties.getBoolean("pinner.pin_camera", false));
     // Pin using pinlist.meta when pinning apps.
     private static boolean PROP_PIN_PINLIST = SystemProperties.getBoolean(
             "pinner.use_pinlist", true);
@@ -150,7 +146,13 @@
     /**
      * A set of {@link AppKey} that are configured to be pinned.
      */
-    private final ArraySet<Integer> mPinKeys = new ArraySet<>();
+    @GuardedBy("this")
+    private ArraySet<Integer> mPinKeys;
+
+    // Resource-configured pinner flags;
+    private final boolean mConfiguredToPinCamera;
+    private final boolean mConfiguredToPinHome;
+    private final boolean mConfiguredToPinAssistant;
 
     private BinderService mBinderService;
     private PinnerHandler mPinnerHandler = null;
@@ -173,25 +175,13 @@
         super(context);
 
         mContext = context;
-        boolean shouldPinCamera = context.getResources().getBoolean(
+        mConfiguredToPinCamera = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_pinnerCameraApp);
-        boolean shouldPinHome = context.getResources().getBoolean(
+        mConfiguredToPinHome = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_pinnerHomeApp);
-        boolean shouldPinAssistant = context.getResources().getBoolean(
+        mConfiguredToPinAssistant = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_pinnerAssistantApp);
-        if (shouldPinCamera) {
-            if (PROP_PIN_CAMERA) {
-                mPinKeys.add(KEY_CAMERA);
-            } else if (DEBUG) {
-                Slog.i(TAG, "Pinner - skip pinning camera app");
-            }
-        }
-        if (shouldPinHome) {
-            mPinKeys.add(KEY_HOME);
-        }
-        if (shouldPinAssistant) {
-            mPinKeys.add(KEY_ASSISTANT);
-        }
+        mPinKeys = createPinKeys();
         mPinnerHandler = new PinnerHandler(BackgroundThread.get().getLooper());
 
         mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
@@ -259,9 +249,10 @@
      * The other files pinned in onStart will not need to be updated.
      */
     public void update(ArraySet<String> updatedPackages, boolean force) {
+        ArraySet<Integer> pinKeys = getPinKeys();
         int currentUser = ActivityManager.getCurrentUser();
-        for (int i = mPinKeys.size() - 1; i >= 0; i--) {
-            int key = mPinKeys.valueAt(i);
+        for (int i = pinKeys.size() - 1; i >= 0; i--) {
+            int key = pinKeys.valueAt(i);
             ApplicationInfo info = getInfoForKey(key, currentUser);
             if (info != null && updatedPackages.contains(info.packageName)) {
                 Slog.i(TAG, "Updating pinned files for " + info.packageName + " force=" + force);
@@ -385,6 +376,14 @@
         }
     }
 
+    private void unpinApps() {
+        ArraySet<Integer> pinKeys = getPinKeys();
+        for (int i = pinKeys.size() - 1; i >= 0; i--) {
+            int key = pinKeys.valueAt(i);
+            unpinApp(key);
+        }
+    }
+
     private void unpinApp(@AppKey int key) {
         ArrayList<PinnedFile> pinnedAppFiles;
         synchronized (this) {
@@ -490,9 +489,79 @@
                 userHandle));
     }
 
+    private void sendPinAppsWithUpdatedKeysMessage(int userHandle) {
+        mPinnerHandler.sendMessage(PooledLambda.obtainMessage(PinnerService::pinAppsWithUpdatedKeys,
+                this, userHandle));
+    }
+    private void sendUnpinAppsMessage() {
+        mPinnerHandler.sendMessage(PooledLambda.obtainMessage(PinnerService::unpinApps, this));
+    }
+
+    private ArraySet<Integer> createPinKeys() {
+        ArraySet<Integer> pinKeys = new ArraySet<>();
+        // Pin the camera application. Default to the system property only if the experiment
+        // phenotype property is not set.
+        boolean shouldPinCamera = mConfiguredToPinCamera
+                && DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT,
+                        "pin_camera",
+                        SystemProperties.getBoolean("pinner.pin_camera", false));
+        if (shouldPinCamera) {
+            pinKeys.add(KEY_CAMERA);
+        } else if (DEBUG) {
+            Slog.i(TAG, "Pinner - skip pinning camera app");
+        }
+
+        if (mConfiguredToPinHome) {
+            pinKeys.add(KEY_HOME);
+        }
+        if (mConfiguredToPinAssistant) {
+            pinKeys.add(KEY_ASSISTANT);
+        }
+
+        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;
+    }
+
     private void pinApps(int userHandle) {
-        for (int i = mPinKeys.size() - 1; i >= 0; i--) {
-            int key = mPinKeys.valueAt(i);
+        pinAppsInternal(userHandle, false);
+    }
+
+    private void pinAppsWithUpdatedKeys(int userHandle) {
+        pinAppsInternal(userHandle, true);
+    }
+
+    /**
+     * @param updateKeys True if the pinned app list has to be updated. This is true only when
+     *                   "pinner repin" shell command is requested.
+     */
+    private void pinAppsInternal(int userHandle, boolean updateKeys) {
+        if (updateKeys) {
+            ArraySet<Integer> newKeys = createPinKeys();
+            synchronized (this) {
+                // This code path demands preceding unpinApps() call.
+                if (!mPinnedApps.isEmpty()) {
+                    Slog.e(TAG, "Attempted to update a list of apps, "
+                            + "but apps were already pinned. Skipping.");
+                    return;
+                }
+
+                mPinKeys = newKeys;
+            }
+        }
+
+        ArraySet<Integer> currentPinKeys = getPinKeys();
+        for (int i = currentPinKeys.size() - 1; i >= 0; i--) {
+            int key = currentPinKeys.valueAt(i);
             pinApp(key, userHandle, true /* force */);
         }
     }
@@ -610,19 +679,40 @@
             mPinnedApps.put(key, pinnedApp);
         }
 
+
         // pin APK
-        int pinSizeLimit = getSizeLimitForKey(key);
-        String apk = appInfo.sourceDir;
-        PinnedFile pf = pinFile(apk, pinSizeLimit, /*attemptPinIntrospection=*/true);
-        if (pf == null) {
-            Slog.e(TAG, "Failed to pin " + apk);
-            return;
+        final int pinSizeLimit = getSizeLimitForKey(key);
+        List<String> apks = new ArrayList<>();
+        apks.add(appInfo.sourceDir);
+
+        if (shouldPinSplitApks() && appInfo.splitSourceDirs != null) {
+            for (String splitApk : appInfo.splitSourceDirs) {
+                apks.add(splitApk);
+            }
         }
-        if (DEBUG) {
-            Slog.i(TAG, "Pinned " + pf.fileName);
-        }
-        synchronized (this) {
-            pinnedApp.mFiles.add(pf);
+
+        int apkPinSizeLimit = pinSizeLimit;
+        for (String apk: apks) {
+            if (apkPinSizeLimit <= 0) {
+                Slog.w(TAG, "Reached to the pin size limit. Skipping: " + apk);
+                // Continue instead of break to print all skipped APK names.
+                continue;
+            }
+
+            PinnedFile pf = pinFile(apk, apkPinSizeLimit, /*attemptPinIntrospection=*/true);
+            if (pf == null) {
+                Slog.e(TAG, "Failed to pin " + apk);
+                continue;
+            }
+
+            if (DEBUG) {
+                Slog.i(TAG, "Pinned " + pf.fileName);
+            }
+            synchronized (this) {
+                pinnedApp.mFiles.add(pf);
+            }
+
+            apkPinSizeLimit -= pf.bytesPinned;
         }
 
         // determine the ABI from either ApplicationInfo or Build
@@ -641,7 +731,7 @@
 
         //not pinning the oat/odex is not a fatal error
         for (String file : files) {
-            pf = pinFile(file, pinSizeLimit, /*attemptPinIntrospection=*/false);
+            PinnedFile pf = pinFile(file, pinSizeLimit, /*attemptPinIntrospection=*/false);
             if (pf != null) {
                 synchronized (this) {
                     if (PROP_PIN_ODEX) {
@@ -981,6 +1071,42 @@
                 }
             }
         }
+
+        private void repin() {
+            sendUnpinAppsMessage();
+            // TODO(morrita): Consider supporting non-system user.
+            sendPinAppsWithUpdatedKeysMessage(UserHandle.USER_SYSTEM);
+        }
+
+        private void printError(FileDescriptor out, String message) {
+            PrintWriter writer = new PrintWriter(new FileOutputStream(out));
+            writer.println(message);
+            writer.flush();
+        }
+
+        @Override
+        public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+                String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
+            if (args.length < 1) {
+                printError(out, "Command is not given.");
+                resultReceiver.send(-1, null);
+                return;
+            }
+
+            String command = args[0];
+            switch (command) {
+                case "repin":
+                    repin();
+                    break;
+                default:
+                    printError(out, String.format(
+                            "Unknown pinner command: %s. Supported commands: repin", command));
+                    resultReceiver.send(-1, null);
+                    return;
+            }
+
+            resultReceiver.send(0, null);
+        }
     }
 
     private static final class PinnedFile implements AutoCloseable {
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index 9ba71dc..e99bb24 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -283,11 +283,16 @@
                 mIndividualEnabled.put(userId, userIndividualEnabled);
 
                 if (!enable) {
-                    // Remove any notifications prompting the user to disable sensory privacy
-                    NotificationManager notificationManager =
-                            mContext.getSystemService(NotificationManager.class);
+                    long token = Binder.clearCallingIdentity();
+                    try {
+                        // Remove any notifications prompting the user to disable sensory privacy
+                        NotificationManager notificationManager =
+                                mContext.getSystemService(NotificationManager.class);
 
-                    notificationManager.cancel(sensor);
+                        notificationManager.cancel(sensor);
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
                 }
                 persistSensorPrivacyState();
             }
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index c951fd4..cd6a9fb 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -1442,6 +1442,9 @@
             mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
 
         } else if (vol.type == VolumeInfo.TYPE_STUB) {
+            if (vol.disk.isStubVisible()) {
+                vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
+            }
             vol.mountUserId = mCurrentUserId;
             mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
         } else {
@@ -1523,7 +1526,6 @@
         }
     }
 
-
     private void onVolumeStateChangedAsync(VolumeInfo vol, int oldState, int newState) {
         synchronized (mLock) {
             // Remember that we saw this volume so we're ready to accept user
@@ -3272,6 +3274,27 @@
         }
     }
 
+    /*
+     * Disable storage's app data isolation for testing.
+     */
+    @Override
+    public void disableAppDataIsolation(String pkgName, int pid, int userId) {
+        final int callingUid = Binder.getCallingUid();
+        if (callingUid != Process.ROOT_UID && callingUid != Process.SHELL_UID) {
+            throw new SecurityException("no permission to enable app visibility");
+        }
+        final String[] sharedPackages =
+                mPmInternal.getSharedUserPackagesForPackage(pkgName, userId);
+        final int uid = mPmInternal.getPackageUid(pkgName, 0, userId);
+        final String[] packages =
+                sharedPackages.length != 0 ? sharedPackages : new String[]{pkgName};
+        try {
+            mVold.unmountAppStorageDirs(uid, pid, packages);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
     /** Not thread safe */
     class AppFuseMountScope extends AppFuseBridge.MountScope {
         private boolean mMounted = false;
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index b76f3278..dde182b 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -564,8 +564,7 @@
             mPreciseDataConnectionStates.add(new ArrayMap<>());
             mBarringInfo.add(i, new BarringInfo());
             mTelephonyDisplayInfos[i] = null;
-            mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig(
-                    PhysicalChannelConfig.CONNECTION_UNKNOWN,0));
+            mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig.Builder().build());
         }
     }
 
@@ -656,8 +655,7 @@
             mPreciseDataConnectionStates.add(new ArrayMap<>());
             mBarringInfo.add(i, new BarringInfo());
             mTelephonyDisplayInfos[i] = null;
-            mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig(
-                    PhysicalChannelConfig.CONNECTION_UNKNOWN,0));
+            mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig.Builder().build());
         }
 
         mAppOps = mContext.getSystemService(AppOpsManager.class);
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index c191a78..2fdc796 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -26,6 +26,7 @@
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.vcn.IVcnManagementService;
+import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
 import android.net.vcn.VcnConfig;
 import android.os.Binder;
 import android.os.Handler;
@@ -495,4 +496,20 @@
             return Collections.unmodifiableMap(mVcns);
         }
     }
+
+    /** Adds the provided listener for receiving VcnUnderlyingNetworkPolicy updates. */
+    @Override
+    public void addVcnUnderlyingNetworkPolicyListener(
+            IVcnUnderlyingNetworkPolicyListener listener) {
+        // TODO(b/175739863): implement policy listener registration
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
+
+    /** Removes the provided listener from receiving VcnUnderlyingNetworkPolicy updates. */
+    @Override
+    public void removeVcnUnderlyingNetworkPolicyListener(
+            IVcnUnderlyingNetworkPolicyListener listener) {
+        // TODO(b/175739863): implement policy listener unregistration
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
 }
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 6a9715e..2c83da5 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -28,6 +28,7 @@
 import android.hardware.vibrator.IVibrator;
 import android.os.BatteryStats;
 import android.os.Binder;
+import android.os.CombinedVibrationEffect;
 import android.os.ExternalVibration;
 import android.os.Handler;
 import android.os.IBinder;
@@ -37,18 +38,15 @@
 import android.os.Looper;
 import android.os.PowerManager;
 import android.os.Process;
-import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
 import android.os.ShellCallback;
 import android.os.ShellCommand;
-import android.os.SystemClock;
 import android.os.Trace;
 import android.os.VibrationAttributes;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.os.VibratorInfo;
-import android.os.WorkSource;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 
@@ -56,11 +54,11 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.util.DumpUtils;
-import com.android.internal.util.FrameworkStatsLog;
 import com.android.server.vibrator.InputDeviceDelegate;
 import com.android.server.vibrator.Vibration;
 import com.android.server.vibrator.VibrationScaler;
 import com.android.server.vibrator.VibrationSettings;
+import com.android.server.vibrator.VibrationThread;
 import com.android.server.vibrator.VibratorController;
 import com.android.server.vibrator.VibratorController.OnVibrationCompleteListener;
 
@@ -90,10 +88,10 @@
     private final LinkedList<Vibration.DebugInfo> mPreviousExternalVibrations;
     private final LinkedList<Vibration.DebugInfo> mPreviousVibrations;
     private final int mPreviousVibrationsLimit;
-    private final WorkSource mTmpWorkSource = new WorkSource();
     private final Handler mH;
     private final Object mLock = new Object();
     private final VibratorController mVibratorController;
+    private final VibrationCallbacks mVibrationCallbacks = new VibrationCallbacks();
 
     private final Context mContext;
     private final PowerManager.WakeLock mWakeLock;
@@ -104,16 +102,40 @@
     private VibrationScaler mVibrationScaler;
     private InputDeviceDelegate mInputDeviceDelegate;
 
-    private volatile VibrateWaveformThread mThread;
+    private volatile VibrationThread mThread;
 
     @GuardedBy("mLock")
     private Vibration mCurrentVibration;
-    @GuardedBy("mLock")
-    private VibrationDeathRecipient mCurrentVibrationDeathRecipient;
     private int mCurVibUid = -1;
     private ExternalVibrationHolder mCurrentExternalVibration;
 
     /**
+     * Implementation of {@link VibrationThread.VibrationCallbacks} that reports finished
+     * vibrations.
+     */
+    private final class VibrationCallbacks implements VibrationThread.VibrationCallbacks {
+
+        @Override
+        public void prepareSyncedVibration(int requiredCapabilities, int[] vibratorIds) {
+        }
+
+        @Override
+        public void triggerSyncedVibration(long vibrationId) {
+        }
+
+        @Override
+        public void onVibrationEnded(long vibrationId, Vibration.Status status) {
+            if (DEBUG) {
+                Slog.d(TAG, "Vibration thread finished with status " + status);
+            }
+            synchronized (mLock) {
+                mThread = null;
+                reportFinishVibrationLocked(status);
+            }
+        }
+    }
+
+    /**
      * Implementation of {@link OnVibrationCompleteListener} with a weak reference to this service.
      */
     private static final class VibrationCompleteListener implements OnVibrationCompleteListener {
@@ -127,41 +149,11 @@
         public void onComplete(int vibratorId, long vibrationId) {
             VibratorService service = mServiceRef.get();
             if (service != null) {
-                service.onVibrationComplete(vibrationId);
+                service.onVibrationComplete(vibratorId, vibrationId);
             }
         }
     }
 
-    /** Death recipient to bind {@link Vibration}. */
-    private final class VibrationDeathRecipient implements IBinder.DeathRecipient {
-
-        private final Vibration mVibration;
-
-        private VibrationDeathRecipient(Vibration vibration) {
-            mVibration = vibration;
-        }
-
-        @Override
-        public void binderDied() {
-            synchronized (mLock) {
-                if (mVibration == mCurrentVibration) {
-                    if (DEBUG) {
-                        Slog.d(TAG, "Vibration finished because binder died, cleaning up");
-                    }
-                    doCancelVibrateLocked(Vibration.Status.CANCELLED);
-                }
-            }
-        }
-
-        private void linkToDeath() throws RemoteException {
-            mVibration.token.linkToDeath(this, 0);
-        }
-
-        private void unlinkToDeath() {
-            mVibration.token.unlinkToDeath(this, 0);
-        }
-    }
-
     /** Holder for a {@link ExternalVibration}. */
     private final class ExternalVibrationHolder {
 
@@ -262,13 +254,20 @@
 
     /** Callback for when vibration is complete, to be called by native. */
     @VisibleForTesting
-    public void onVibrationComplete(long vibrationId) {
+    public void onVibrationComplete(int vibratorId, long vibrationId) {
         synchronized (mLock) {
             if (mCurrentVibration != null && mCurrentVibration.id == vibrationId) {
                 if (DEBUG) {
-                    Slog.d(TAG, "Vibration finished by callback, cleaning up");
+                    Slog.d(TAG, "Vibration onComplete callback, notifying VibrationThread");
                 }
-                doCancelVibrateLocked(Vibration.Status.FINISHED);
+                if (mThread != null) {
+                    // Let the thread playing the vibration handle the callback, since it might be
+                    // expecting the vibrator to turn off multiple times during a single vibration.
+                    mThread.vibratorComplete(vibratorId);
+                } else {
+                    // No vibration is playing in the thread, but clean up service just in case.
+                    doCancelVibrateLocked(Vibration.Status.FINISHED);
+                }
             }
         }
     }
@@ -354,6 +353,17 @@
         return true;
     }
 
+    private VibrationEffect fixupVibrationEffect(VibrationEffect effect) {
+        if (effect instanceof VibrationEffect.Prebaked
+                && ((VibrationEffect.Prebaked) effect).shouldFallback()) {
+            VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) effect;
+            VibrationEffect fallback = mVibrationSettings.getFallbackEffect(prebaked.getId());
+            return new VibrationEffect.Prebaked(prebaked.getId(), prebaked.getEffectStrength(),
+                    fallback);
+        }
+        return effect;
+    }
+
     private VibrationAttributes fixupVibrationAttributes(VibrationAttributes attrs) {
         if (attrs == null) {
             attrs = DEFAULT_ATTRIBUTES;
@@ -388,16 +398,16 @@
             if (!verifyVibrationEffect(effect)) {
                 return;
             }
-
+            effect = fixupVibrationEffect(effect);
             attrs = fixupVibrationAttributes(attrs);
-            Vibration vib = new Vibration(token, mNextVibrationId.getAndIncrement(), effect, attrs,
-                    uid, opPkg, reason);
+            Vibration vib = new Vibration(token, mNextVibrationId.getAndIncrement(),
+                    CombinedVibrationEffect.createSynced(effect), attrs, uid, opPkg, reason);
 
             // If our current vibration is longer than the new vibration and is the same amplitude,
             // then just let the current one finish.
             synchronized (mLock) {
                 VibrationEffect currentEffect =
-                        mCurrentVibration == null ? null : mCurrentVibration.getEffect();
+                        mCurrentVibration == null ? null : getEffect(mCurrentVibration);
                 if (effect instanceof VibrationEffect.OneShot
                         && currentEffect instanceof VibrationEffect.OneShot) {
                     VibrationEffect.OneShot newOneShot = (VibrationEffect.OneShot) effect;
@@ -446,7 +456,6 @@
                     endVibrationLocked(vib, Vibration.Status.IGNORED_BACKGROUND);
                     return;
                 }
-                linkVibrationLocked(vib);
                 final long ident = Binder.clearCallingIdentity();
                 try {
                     doCancelVibrateLocked(Vibration.Status.CANCELLED);
@@ -474,6 +483,10 @@
         return effect.getDuration() == Long.MAX_VALUE;
     }
 
+    private static <T extends VibrationEffect> T getEffect(Vibration vib) {
+        return (T) ((CombinedVibrationEffect.Mono) vib.getEffect()).getEffect();
+    }
+
     private void endVibrationLocked(Vibration vib, Vibration.Status status) {
         final LinkedList<Vibration.DebugInfo> previousVibrations;
         switch (vib.attrs.getUsage()) {
@@ -527,7 +540,6 @@
 
     @GuardedBy("mLock")
     private void doCancelVibrateLocked(Vibration.Status status) {
-        Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doCancelVibrateLocked");
         try {
             if (mThread != null) {
@@ -547,18 +559,6 @@
         }
     }
 
-    // Callback for whenever the current vibration has finished played out
-    public void onVibrationFinished() {
-        if (DEBUG) {
-            Slog.d(TAG, "Vibration finished, cleaning up");
-        }
-        synchronized (mLock) {
-            // Make sure the vibration is really done. This also reports that the vibration is
-            // finished.
-            doCancelVibrateLocked(Vibration.Status.FINISHED);
-        }
-    }
-
     @GuardedBy("mLock")
     private void startVibrationLocked(final Vibration vib) {
         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationLocked");
@@ -579,24 +579,20 @@
         try {
             // Set current vibration before starting it, so callback will work.
             mCurrentVibration = vib;
-            VibrationEffect effect = vib.getEffect();
-            if (effect instanceof VibrationEffect.OneShot) {
-                Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
-                doVibratorOn(vib);
-            } else if (effect instanceof VibrationEffect.Waveform) {
-                Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
-                doVibratorWaveformEffectLocked(vib);
-            } else if (effect instanceof VibrationEffect.Prebaked) {
-                Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
-                doVibratorPrebakedEffectLocked(vib);
-            } else if (effect instanceof VibrationEffect.Composed) {
-                Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
-                doVibratorComposedEffectLocked(vib);
-            } else {
-                Slog.e(TAG, "Unknown vibration type, ignoring");
-                endVibrationLocked(vib, Vibration.Status.IGNORED_UNKNOWN_VIBRATION);
-                // The set current vibration is not actually playing, so drop it.
+            VibrationEffect effect = getEffect(vib);
+            Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
+            boolean inputDevicesAvailable = mInputDeviceDelegate.vibrateIfAvailable(
+                    vib.uid, vib.opPkg, vib.getEffect(), vib.reason, vib.attrs);
+            if (inputDevicesAvailable) {
+                // The set current vibration is no longer being played by this service, so drop it.
                 mCurrentVibration = null;
+                endVibrationLocked(vib, Vibration.Status.FORWARDED_TO_INPUT_DEVICES);
+            } else {
+                // mThread better be null here. doCancelVibrate should always be
+                // called before startVibrationInnerLocked
+                mThread = new VibrationThread(vib, mVibratorController, mWakeLock,
+                        mBatteryStatsService, mVibrationCallbacks);
+                mThread.start();
             }
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
@@ -667,13 +663,13 @@
 
     @GuardedBy("mLock")
     private void reportFinishVibrationLocked(Vibration.Status status) {
+        Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked");
         try {
             if (mCurrentVibration != null) {
                 endVibrationLocked(mCurrentVibration, status);
                 mAppOps.finishOp(AppOpsManager.OP_VIBRATE, mCurrentVibration.uid,
                         mCurrentVibration.opPkg);
-                unlinkVibrationLocked();
                 mCurrentVibration = null;
             }
         } finally {
@@ -681,30 +677,6 @@
         }
     }
 
-    @GuardedBy("mLock")
-    private void linkVibrationLocked(Vibration vib) {
-        // Unlink previously linked vibration, if any.
-        unlinkVibrationLocked();
-        // Only link against waveforms since they potentially don't have a finish if
-        // they're repeating. Let other effects just play out until they're done.
-        if (vib.getEffect() instanceof VibrationEffect.Waveform) {
-            try {
-                mCurrentVibrationDeathRecipient = new VibrationDeathRecipient(vib);
-                mCurrentVibrationDeathRecipient.linkToDeath();
-            } catch (RemoteException e) {
-                return;
-            }
-        }
-    }
-
-    @GuardedBy("mLock")
-    private void unlinkVibrationLocked() {
-        if (mCurrentVibrationDeathRecipient != null) {
-            mCurrentVibrationDeathRecipient.unlinkToDeath();
-            mCurrentVibrationDeathRecipient = null;
-        }
-    }
-
     private void updateVibrators() {
         synchronized (mLock) {
             mInputDeviceDelegate.updateInputDeviceVibrators(
@@ -715,40 +687,12 @@
         }
     }
 
-    private void doVibratorOn(Vibration vib) {
-        Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOn");
-        try {
-            final VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.getEffect();
-            if (DEBUG) {
-                Slog.d(TAG, "Turning vibrator on for " + oneShot.getDuration() + " ms"
-                        + " with amplitude " + oneShot.getAmplitude() + ".");
-            }
-            boolean inputDevicesAvailable = mInputDeviceDelegate.vibrateIfAvailable(
-                    vib.uid, vib.opPkg, oneShot, vib.reason, vib.attrs);
-            if (inputDevicesAvailable) {
-                // The set current vibration is no longer being played by this service, so drop it.
-                mCurrentVibration = null;
-                endVibrationLocked(vib, Vibration.Status.FORWARDED_TO_INPUT_DEVICES);
-            } else {
-                noteVibratorOnLocked(vib.uid, oneShot.getDuration());
-                // Note: ordering is important here! Many haptic drivers will reset their
-                // amplitude when enabled, so we always have to enable first, then set the
-                // amplitude.
-                mVibratorController.on(oneShot.getDuration(), vib.id);
-                mVibratorController.setAmplitude(oneShot.getAmplitude());
-            }
-        } finally {
-            Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
-        }
-    }
-
     private void doVibratorOff() {
         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOff");
         try {
             if (DEBUG) {
                 Slog.d(TAG, "Turning vibrator off.");
             }
-            noteVibratorOffLocked();
             boolean inputDevicesAvailable = mInputDeviceDelegate.cancelVibrateIfAvailable();
             if (!inputDevicesAvailable) {
                 mVibratorController.off();
@@ -758,95 +702,6 @@
         }
     }
 
-    @GuardedBy("mLock")
-    private void doVibratorWaveformEffectLocked(Vibration vib) {
-        Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorWaveformEffectLocked");
-        try {
-            boolean inputDevicesAvailable = mInputDeviceDelegate.vibrateIfAvailable(
-                    vib.uid, vib.opPkg, vib.getEffect(), vib.reason, vib.attrs);
-            if (inputDevicesAvailable) {
-                // The set current vibration is no longer being played by this service, so drop it.
-                mCurrentVibration = null;
-                endVibrationLocked(vib, Vibration.Status.FORWARDED_TO_INPUT_DEVICES);
-            } else {
-                // mThread better be null here. doCancelVibrate should always be
-                // called before startNextVibrationLocked or startVibrationLocked.
-                mThread = new VibrateWaveformThread(vib);
-                mThread.start();
-            }
-        } finally {
-            Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
-        }
-    }
-
-    @GuardedBy("mLock")
-    private void doVibratorPrebakedEffectLocked(Vibration vib) {
-        Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorPrebakedEffectLocked");
-        try {
-            final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.getEffect();
-            // Input devices don't support prebaked effect, so skip trying it with them and allow
-            // fallback to be attempted.
-            if (!mInputDeviceDelegate.isAvailable()) {
-                long duration = mVibratorController.on(prebaked, vib.id);
-                if (duration > 0) {
-                    noteVibratorOnLocked(vib.uid, duration);
-                    return;
-                }
-            }
-            endVibrationLocked(vib, Vibration.Status.IGNORED_UNSUPPORTED);
-            // The set current vibration is not actually playing, so drop it.
-            mCurrentVibration = null;
-
-            if (!prebaked.shouldFallback()) {
-                return;
-            }
-            VibrationEffect effect = mVibrationSettings.getFallbackEffect(prebaked.getId());
-            if (effect == null) {
-                Slog.w(TAG, "Failed to play prebaked effect, no fallback");
-                return;
-            }
-            Vibration fallbackVib = new Vibration(vib.token, mNextVibrationId.getAndIncrement(),
-                    effect, vib.attrs, vib.uid, vib.opPkg, vib.reason + " (fallback)");
-            // Set current vibration before starting it, so callback will work.
-            mCurrentVibration = fallbackVib;
-            linkVibrationLocked(fallbackVib);
-            applyVibrationIntensityScalingLocked(fallbackVib);
-            startVibrationInnerLocked(fallbackVib);
-        } finally {
-            Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
-        }
-    }
-
-    @GuardedBy("mLock")
-    private void doVibratorComposedEffectLocked(Vibration vib) {
-        Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorComposedEffectLocked");
-
-        try {
-            final VibrationEffect.Composed composed = (VibrationEffect.Composed) vib.getEffect();
-            boolean inputDevicesAvailable = mInputDeviceDelegate.vibrateIfAvailable(
-                    vib.uid, vib.opPkg, composed, vib.reason, vib.attrs);
-            if (inputDevicesAvailable) {
-                // The set current vibration is no longer being played by this service, so drop it.
-                mCurrentVibration = null;
-                endVibrationLocked(vib, Vibration.Status.FORWARDED_TO_INPUT_DEVICES);
-                return;
-            } else if (!mVibratorController.hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
-                // The set current vibration is not actually playing, so drop it.
-                mCurrentVibration = null;
-                endVibrationLocked(vib, Vibration.Status.IGNORED_UNSUPPORTED);
-                return;
-            }
-
-            mVibratorController.on(composed, vib.id);
-
-            // Composed effects don't actually give us an estimated duration, so we just guess here.
-            noteVibratorOnLocked(vib.uid, 10 * composed.getPrimitiveEffects().size());
-        } finally {
-            Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
-        }
-
-    }
-
     private boolean isSystemHapticFeedback(Vibration vib) {
         if (vib.attrs.getUsage() != VibrationAttributes.USAGE_TOUCH) {
             return false;
@@ -854,27 +709,6 @@
         return vib.uid == Process.SYSTEM_UID || vib.uid == 0 || mSystemUiPackage.equals(vib.opPkg);
     }
 
-    private void noteVibratorOnLocked(int uid, long millis) {
-        try {
-            mBatteryStatsService.noteVibratorOn(uid, millis);
-            FrameworkStatsLog.write_non_chained(FrameworkStatsLog.VIBRATOR_STATE_CHANGED, uid, null,
-                    FrameworkStatsLog.VIBRATOR_STATE_CHANGED__STATE__ON, millis);
-            mCurVibUid = uid;
-        } catch (RemoteException e) {
-        }
-    }
-
-    private void noteVibratorOffLocked() {
-        if (mCurVibUid >= 0) {
-            try {
-                mBatteryStatsService.noteVibratorOff(mCurVibUid);
-                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.VIBRATOR_STATE_CHANGED,
-                        mCurVibUid, null, FrameworkStatsLog.VIBRATOR_STATE_CHANGED__STATE__OFF, 0);
-            } catch (RemoteException e) { }
-            mCurVibUid = -1;
-        }
-    }
-
     private void dumpInternal(PrintWriter pw) {
         pw.println("Vibrator Service:");
         synchronized (mLock) {
@@ -972,156 +806,6 @@
         proto.flush();
     }
 
-    /** Thread that plays a single {@link VibrationEffect.Waveform}. */
-    private class VibrateWaveformThread extends Thread {
-        private final VibrationEffect.Waveform mWaveform;
-        private final Vibration mVibration;
-
-        private boolean mForceStop;
-
-        VibrateWaveformThread(Vibration vib) {
-            mWaveform = (VibrationEffect.Waveform) vib.getEffect();
-            mVibration = new Vibration(vib.token, /* id= */ 0, /* effect= */ null, vib.attrs,
-                    vib.uid, vib.opPkg, vib.reason);
-            mTmpWorkSource.set(vib.uid);
-            mWakeLock.setWorkSource(mTmpWorkSource);
-        }
-
-        private void delayLocked(long wakeUpTime) {
-            Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "delayLocked");
-            try {
-                long durationRemaining = wakeUpTime - SystemClock.uptimeMillis();
-                while (durationRemaining > 0) {
-                    try {
-                        this.wait(durationRemaining);
-                    } catch (InterruptedException e) {
-                    }
-                    if (mForceStop) {
-                        break;
-                    }
-                    durationRemaining = wakeUpTime - SystemClock.uptimeMillis();
-                }
-            } finally {
-                Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
-            }
-        }
-
-        public void run() {
-            Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
-            mWakeLock.acquire();
-            try {
-                boolean finished = playWaveform();
-                if (finished) {
-                    onVibrationFinished();
-                }
-            } finally {
-                mWakeLock.release();
-            }
-        }
-
-        /**
-         * Play the waveform.
-         *
-         * @return true if it finished naturally, false otherwise (e.g. it was canceled).
-         */
-        public boolean playWaveform() {
-            Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "playWaveform");
-            try {
-                synchronized (this) {
-                    final long[] timings = mWaveform.getTimings();
-                    final int[] amplitudes = mWaveform.getAmplitudes();
-                    final int len = timings.length;
-                    final int repeat = mWaveform.getRepeatIndex();
-
-                    int index = 0;
-                    long nextStepStartTime = SystemClock.uptimeMillis();
-                    long nextVibratorStopTime = 0;
-                    while (!mForceStop) {
-                        if (index < len) {
-                            final int amplitude = amplitudes[index];
-                            final long duration = timings[index++];
-                            if (duration <= 0) {
-                                continue;
-                            }
-                            if (amplitude != 0) {
-                                long now = SystemClock.uptimeMillis();
-                                if (nextVibratorStopTime <= now) {
-                                    // Telling the vibrator to start multiple times usually causes
-                                    // effects to feel "choppy" because the motor resets at every on
-                                    // command.  Instead we figure out how long our next "on" period
-                                    // is going to be, tell the motor to stay on for the full
-                                    // duration, and then wake up to change the amplitude at the
-                                    // appropriate intervals.
-                                    long onDuration = getTotalOnDuration(
-                                            timings, amplitudes, index - 1, repeat);
-                                    mVibration.updateEffect(
-                                            VibrationEffect.createOneShot(onDuration, amplitude));
-                                    doVibratorOn(mVibration);
-                                    nextVibratorStopTime = now + onDuration;
-                                } else {
-                                    // Vibrator is already ON, so just change its amplitude.
-                                    mVibratorController.setAmplitude(amplitude);
-                                }
-                            } else {
-                                // Previous vibration should have already finished, but we make sure
-                                // the vibrator will be off for the next step when amplitude is 0.
-                                doVibratorOff();
-                            }
-
-                            // We wait until the time this waveform step was supposed to end,
-                            // calculated from the time it was supposed to start. All start times
-                            // are calculated from the waveform original start time by adding the
-                            // input durations. Any scheduling or processing delay should not affect
-                            // this step's perceived total duration. They will be amortized here.
-                            nextStepStartTime += duration;
-                            delayLocked(nextStepStartTime);
-                        } else if (repeat < 0) {
-                            break;
-                        } else {
-                            index = repeat;
-                        }
-                    }
-                    return !mForceStop;
-                }
-            } finally {
-                Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
-            }
-        }
-
-        public void cancel() {
-            synchronized (this) {
-                mThread.mForceStop = true;
-                mThread.notify();
-            }
-        }
-
-        /**
-         * Get the duration the vibrator will be on starting at startIndex until the next time it's
-         * off.
-         */
-        private long getTotalOnDuration(
-                long[] timings, int[] amplitudes, int startIndex, int repeatIndex) {
-            int i = startIndex;
-            long timing = 0;
-            while (amplitudes[i] != 0) {
-                timing += timings[i++];
-                if (i >= timings.length) {
-                    if (repeatIndex >= 0) {
-                        i = repeatIndex;
-                        // prevent infinite loop
-                        repeatIndex = -1;
-                    } else {
-                        break;
-                    }
-                }
-                if (i == startIndex) {
-                    return 1000;
-                }
-            }
-            return timing;
-        }
-    }
-
     /** Point of injection for test dependencies */
     @VisibleForTesting
     static class Injector {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 88bb1a0..5cc3274 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1692,7 +1692,7 @@
             }
 
             try {
-                String ignoreForeground = null;
+                boolean ignoreForeground = false;
                 final int mode = mAm.getAppOpsManager().checkOpNoThrow(
                         AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName);
                 switch (mode) {
@@ -1702,9 +1702,9 @@
                         break;
                     case AppOpsManager.MODE_IGNORED:
                         // Whoops, silently ignore this.
-                        ignoreForeground = "Service.startForeground() not allowed due to app op: "
-                                + "service " + r.shortInstanceName;
-                        Slog.w(TAG, ignoreForeground);
+                        Slog.w(TAG, "Service.startForeground() not allowed due to app op: service "
+                                + r.shortInstanceName);
+                        ignoreForeground = true;
                         break;
                     default:
                         throw new SecurityException("Foreground not allowed as per app op");
@@ -1712,18 +1712,19 @@
 
                 // Apps that are TOP or effectively similar may call startForeground() on
                 // their services even if they are restricted from doing that while in bg.
-                if (ignoreForeground == null
+                if (!ignoreForeground
                         && !appIsTopLocked(r.appInfo.uid)
                         && appRestrictedAnyInBackground(r.appInfo.uid, r.packageName)) {
-                    ignoreForeground = "Service.startForeground() not allowed due to bg restriction"
-                            + ":service " + r.shortInstanceName;
-                    Slog.w(TAG, ignoreForeground);
+                    Slog.w(TAG,
+                            "Service.startForeground() not allowed due to bg restriction: service "
+                                    + r.shortInstanceName);
                     // Back off of any foreground expectations around this service, since we've
                     // just turned down its fg request.
                     updateServiceForegroundLocked(r.app, false);
+                    ignoreForeground = true;
                 }
 
-                if (ignoreForeground == null) {
+                if (!ignoreForeground) {
                     if (isFgsBgStart(r.mAllowStartForeground)) {
                         if (!r.mLoggedInfoAllowStartForeground) {
                             Slog.wtf(TAG, "Background started FGS "
@@ -1732,12 +1733,17 @@
                         }
                         if (r.mAllowStartForeground == FGS_FEATURE_DENIED
                                 && isBgFgsRestrictionEnabled(r)) {
-                            ignoreForeground = "Service.startForeground() not allowed due to "
+                            final String msg = "Service.startForeground() not allowed due to "
                                     + "mAllowStartForeground false: service "
                                     + r.shortInstanceName;
-                            Slog.w(TAG, ignoreForeground);
+                            Slog.w(TAG, msg);
                             showFgsBgRestrictedNotificationLocked(r);
                             updateServiceForegroundLocked(r.app, true);
+                            ignoreForeground = true;
+                            if (CompatChanges.isChangeEnabled(FGS_START_EXCEPTION_CHANGE_ID,
+                                    r.appInfo.uid)) {
+                                throw new IllegalStateException(msg);
+                            }
                         }
                     }
                 }
@@ -1746,7 +1752,7 @@
                 // services, so now that we've enforced the startForegroundService() contract
                 // we only do the machinery of making the service foreground when the app
                 // is not restricted.
-                if (ignoreForeground == null) {
+                if (!ignoreForeground) {
                     if (r.foregroundId != id) {
                         cancelForegroundNotificationLocked(r);
                         r.foregroundId = id;
@@ -1808,10 +1814,6 @@
                     if (DEBUG_FOREGROUND_SERVICE) {
                         Slog.d(TAG, "Suppressing startForeground() for FAS " + r);
                     }
-                    if (CompatChanges.isChangeEnabled(FGS_START_EXCEPTION_CHANGE_ID, r.appInfo.uid)
-                            && isBgFgsRestrictionEnabled(r)) {
-                        throw new IllegalStateException(ignoreForeground);
-                    }
                 }
             } finally {
                 if (stopProcStatsOp) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b587f1b..1f48aeb 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -32,6 +32,7 @@
 import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
 import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
 import static android.app.AppOpsManager.OP_NONE;
+import static android.app.BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
 import static android.content.pm.ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT;
 import static android.content.pm.PackageManager.GET_SHARED_LIBRARY_FILES;
 import static android.content.pm.PackageManager.MATCH_ALL;
@@ -1085,11 +1086,13 @@
         final int targetUid;
         final long duration;
         final String tag;
+        final int type;
 
-        PendingTempWhitelist(int _targetUid, long _duration, String _tag) {
+        PendingTempWhitelist(int _targetUid, long _duration, String _tag, int _type) {
             targetUid = _targetUid;
             duration = _duration;
             tag = _tag;
+            type = _type;
         }
 
         void dumpDebug(ProtoOutputStream proto, long fieldId) {
@@ -1097,6 +1100,7 @@
             proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.TARGET_UID, targetUid);
             proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.DURATION_MS, duration);
             proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.TAG, tag);
+            proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.TYPE, type);
             proto.end(token);
         }
     }
@@ -5526,8 +5530,7 @@
     }
 
     boolean isWhitelistedForFgsStartLocked(int uid) {
-        final int appId = UserHandle.getAppId(uid);
-        return Arrays.binarySearch(mDeviceIdleExceptIdleWhitelist, appId) >= 0
+        return Arrays.binarySearch(mDeviceIdleExceptIdleWhitelist, UserHandle.getAppId(uid)) >= 0
                 || mFgsStartTempAllowList.isAllowed(uid);
     }
 
@@ -8302,6 +8305,7 @@
         synchronized(this) {
             mConstants.dump(pw);
             mOomAdjuster.dumpCachedAppOptimizerSettings(pw);
+            mOomAdjuster.dumpCacheOomRankerSettings(pw);
             pw.println();
             if (dumpAll) {
                 pw.println("-------------------------------------------------------------------------------");
@@ -8722,6 +8726,7 @@
                 synchronized (this) {
                     mConstants.dump(pw);
                     mOomAdjuster.dumpCachedAppOptimizerSettings(pw);
+                    mOomAdjuster.dumpCacheOomRankerSettings(pw);
                 }
             } else if ("services".equals(cmd) || "s".equals(cmd)) {
                 if (dumpClient) {
@@ -9296,6 +9301,8 @@
                     TimeUtils.formatDuration(ptw.duration, pw);
                     pw.print(" ");
                     pw.println(ptw.tag);
+                    pw.print(" ");
+                    pw.print(ptw.type);
                 }
             }
         }
@@ -15357,11 +15364,12 @@
      */
     @GuardedBy("this")
     void tempWhitelistUidLocked(int targetUid, long duration, String tag, int type) {
-        mPendingTempWhitelist.put(targetUid, new PendingTempWhitelist(targetUid, duration, tag));
+        mPendingTempWhitelist.put(targetUid,
+                new PendingTempWhitelist(targetUid, duration, tag, type));
         setUidTempWhitelistStateLocked(targetUid, true);
         mUiHandler.obtainMessage(PUSH_TEMP_WHITELIST_UI_MSG).sendToTarget();
 
-        if (type == BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED) {
+        if (type == TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED) {
             mFgsStartTempAllowList.add(targetUid, duration);
         }
     }
@@ -15387,7 +15395,7 @@
             for (int i = 0; i < N; i++) {
                 PendingTempWhitelist ptw = list[i];
                 mLocalDeviceIdleController.addPowerSaveTempWhitelistAppDirect(ptw.targetUid,
-                        ptw.duration, true, ptw.tag);
+                        ptw.duration, ptw.type, true, ptw.tag);
             }
         }
 
@@ -15404,8 +15412,8 @@
     }
 
     @GuardedBy("this")
-    final void setAppIdTempWhitelistStateLocked(int appId, boolean onWhitelist) {
-        mOomAdjuster.setAppIdTempWhitelistStateLocked(appId, onWhitelist);
+    final void setAppIdTempWhitelistStateLocked(int uid, boolean onWhitelist) {
+        mOomAdjuster.setAppIdTempWhitelistStateLocked(uid, onWhitelist);
     }
 
     @GuardedBy("this")
@@ -15713,6 +15721,16 @@
     }
 
     @Override
+    public boolean startProfile(@UserIdInt int userId) {
+        return mUserController.startProfile(userId);
+    }
+
+    @Override
+    public boolean stopProfile(@UserIdInt int userId) {
+        return mUserController.stopProfile(userId);
+    }
+
+    @Override
     public UserInfo getCurrentUser() {
         return mUserController.getCurrentUser();
     }
@@ -15997,10 +16015,16 @@
         }
 
         @Override
-        public void updateDeviceIdleTempWhitelist(int[] appids, int changingAppId, boolean adding) {
+        public void updateDeviceIdleTempWhitelist(int[] appids, int changingUid, boolean adding,
+                long durationMs, @BroadcastOptions.TempAllowListType int type) {
             synchronized (ActivityManagerService.this) {
                 mDeviceIdleTempWhitelist = appids;
-                setAppIdTempWhitelistStateLocked(changingAppId, adding);
+                if (adding) {
+                    if (type == TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED) {
+                        mFgsStartTempAllowList.add(changingUid, durationMs);
+                    }
+                }
+                setAppIdTempWhitelistStateLocked(changingUid, adding);
             }
         }
 
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 6fe934e..ada7eea 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -17,21 +17,24 @@
 
 import static com.android.internal.power.MeasuredEnergyArray.SUBSYSTEM_DISPLAY;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.bluetooth.BluetoothActivityEnergyInfo;
 import android.bluetooth.BluetoothAdapter;
 import android.content.Context;
+import android.hardware.power.stats.EnergyConsumerId;
+import android.hardware.power.stats.EnergyConsumerResult;
 import android.net.wifi.WifiManager;
 import android.os.BatteryStats;
 import android.os.Bundle;
 import android.os.OutcomeReceiver;
 import android.os.Parcelable;
 import android.os.Process;
-import android.os.ServiceManager;
 import android.os.SynchronousResultReceiver;
 import android.os.SystemClock;
 import android.os.ThreadLocalWorkSource;
 import android.os.connectivity.WifiActivityEnergyInfo;
+import android.power.PowerStatsInternal;
 import android.telephony.ModemActivityInfo;
 import android.telephony.TelephonyManager;
 import android.util.IntArray;
@@ -41,8 +44,10 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.internal.power.MeasuredEnergyArray;
+import com.android.internal.power.MeasuredEnergyStats;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.server.LocalServices;
 
 import libcore.util.EmptyArray;
 
@@ -91,6 +96,8 @@
                     });
 
     private final Context mContext;
+
+    @GuardedBy("mStats")
     private final BatteryStatsImpl mStats;
 
     @GuardedBy("this")
@@ -123,6 +130,7 @@
     @GuardedBy("this")
     private Future<?> mBatteryLevelSync;
 
+    // If both mStats and mWorkerLock need to be synchronized, mWorkerLock must be acquired first.
     private final Object mWorkerLock = new Object();
 
     @GuardedBy("mWorkerLock")
@@ -131,6 +139,9 @@
     @GuardedBy("mWorkerLock")
     private TelephonyManager mTelephony = null;
 
+    @GuardedBy("mWorkerLock")
+    private PowerStatsInternal mPowerStatsInternal = null;
+
     // WiFi keeps an accumulated total of stats, unlike Bluetooth.
     // Keep the last WiFi stats so we can compute a delta.
     @GuardedBy("mWorkerLock")
@@ -139,7 +150,7 @@
 
     /** Snapshot of measured energies, or null if no measured energies are supported. */
     @GuardedBy("mWorkerLock")
-    private final @Nullable MeasuredEnergySnapshot mMeasuredEnergySnapshot;
+    private @Nullable MeasuredEnergySnapshot mMeasuredEnergySnapshot = null;
 
     /**
      * Timestamp at which all external stats were last collected in
@@ -148,13 +159,27 @@
     @GuardedBy("this")
     private long mLastCollectionTimeStamp;
 
-    BatteryExternalStatsWorker(Context context, BatteryStatsImpl stats,
-            @Nullable MeasuredEnergyArray initialMeasuredEnergies) {
+    BatteryExternalStatsWorker(Context context, BatteryStatsImpl stats) {
         mContext = context;
         mStats = stats;
+    }
 
-        mMeasuredEnergySnapshot = initialMeasuredEnergies == null ?
-                null : new MeasuredEnergySnapshot(initialMeasuredEnergies);
+    public void systemServicesReady() {
+        final WifiManager wm = mContext.getSystemService(WifiManager.class);
+        final TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
+        final PowerStatsInternal psi = LocalServices.getService(PowerStatsInternal.class);
+        final MeasuredEnergyArray initialMeasuredEnergies = getEnergyConsumptionData(psi);
+        final boolean[] supportedBuckets = getSupportedEnergyBuckets(initialMeasuredEnergies);
+        synchronized (mWorkerLock) {
+            mWifiManager = wm;
+            mTelephony = tm;
+            mPowerStatsInternal = psi;
+            mMeasuredEnergySnapshot = initialMeasuredEnergies == null
+                    ? null : new MeasuredEnergySnapshot(initialMeasuredEnergies);
+            synchronized (mStats) {
+                mStats.initMeasuredEnergyStatsLocked(supportedBuckets);
+            }
+        }
     }
 
     @Override
@@ -433,14 +458,6 @@
 
         if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_WIFI) != 0) {
             // We were asked to fetch WiFi data.
-            if (mWifiManager == null && ServiceManager.getService(Context.WIFI_SERVICE) != null) {
-                // this code is reached very early in the boot process, before Wifi Service has
-                // been registered. Check that ServiceManager.getService() returns a non null
-                // value before calling mContext.getSystemService(), since otherwise
-                // getSystemService() will throw a ServiceNotFoundException.
-                mWifiManager = mContext.getSystemService(WifiManager.class);
-            }
-
             // Only fetch WiFi power data if it is supported.
             if (mWifiManager != null && mWifiManager.isEnhancedPowerReportingSupported()) {
                 SynchronousResultReceiver tempWifiReceiver = new SynchronousResultReceiver("wifi");
@@ -478,10 +495,6 @@
 
         if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_RADIO) != 0) {
             // We were asked to fetch Telephony data.
-            if (mTelephony == null) {
-                mTelephony = mContext.getSystemService(TelephonyManager.class);
-            }
-
             if (mTelephony != null) {
                 CompletableFuture<ModemActivityInfo> temp = new CompletableFuture<>();
                 mTelephony.requestModemActivityInfo(Runnable::run,
@@ -689,17 +702,91 @@
         return delta;
     }
 
-    // TODO(b/172934873): Evaluate a safe way to query the HAL without holding mStats
+    /**
+     * Map the {@link MeasuredEnergyArray.MeasuredEnergySubsystem}s in the given energyArray to
+     * their corresponding {@link MeasuredEnergyStats.EnergyBucket}s.
+     *
+     * @return array with true for index i if energy bucket i is supported.
+     */
+    private static @Nullable boolean[] getSupportedEnergyBuckets(MeasuredEnergyArray energyArray) {
+        if (energyArray == null) {
+            return null;
+        }
+        final boolean[] buckets = new boolean[MeasuredEnergyStats.NUMBER_ENERGY_BUCKETS];
+        final int size = energyArray.size();
+        for (int energyIdx = 0; energyIdx < size; energyIdx++) {
+            switch (energyArray.getSubsystem(energyIdx)) {
+                case MeasuredEnergyArray.SUBSYSTEM_DISPLAY:
+                    buckets[MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_ON] = true;
+                    buckets[MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_DOZE] = true;
+                    buckets[MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_OTHER] = true;
+                    break;
+            }
+        }
+        return buckets;
+    }
+
+    /**
+     * Get a {@link MeasuredEnergyArray} with the latest
+     * {@link MeasuredEnergyArray.MeasuredEnergySubsystem} energy usage since boot.
+     *
+     * TODO(b/176988041): Replace {@link MeasuredEnergyArray} usage with {@link
+     * EnergyConsumerResult}[]
+     */
+    private static @Nullable
+            MeasuredEnergyArray getEnergyConsumptionData(@NonNull PowerStatsInternal psi) {
+        final EnergyConsumerResult[] results;
+        try {
+            results = psi.getEnergyConsumedAsync(new int[0])
+                    .get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+        } catch (Exception e) {
+            Slog.e(TAG, "Failed to getEnergyConsumedAsync", e);
+            return null;
+        }
+        if (results == null) return null;
+        final int size = results.length;
+        final int[] subsystems = new int[size];
+        final long[] energyUJ = new long[size];
+
+        for (int i = 0; i < size; i++) {
+            final EnergyConsumerResult consumer = results[i];
+            final int subsystem;
+            switch (consumer.energyConsumerId) {
+                case EnergyConsumerId.DISPLAY:
+                    subsystem = MeasuredEnergyArray.SUBSYSTEM_DISPLAY;
+                    break;
+                default:
+                    continue;
+            }
+            subsystems[i] = subsystem;
+            energyUJ[i] = consumer.energyUWs;
+        }
+        return new MeasuredEnergyArray() {
+            @Override
+            public int getSubsystem(int index) {
+                return subsystems[index];
+            }
+
+            @Override
+            public long getEnergy(int index) {
+                return energyUJ[index];
+            }
+
+            @Override
+            public int size() {
+                return size;
+            }
+        };
+    }
+
     /** Fetch MeasuredEnergyArray for supported subsystems based on the given updateFlags. */
     @GuardedBy("mWorkerLock")
     private @Nullable MeasuredEnergyArray getMeasuredEnergyLocked(@ExternalUpdateFlag int flags) {
-        if (mMeasuredEnergySnapshot == null) return null;
+        if (mMeasuredEnergySnapshot == null || mPowerStatsInternal == null) return null;
 
         if (flags == UPDATE_ALL) {
             // Gotta catch 'em all... including custom (non-specific) subsystems
-            synchronized (mStats) {
-                return mStats.getEnergyConsumptionDataLocked();
-            }
+            return getEnergyConsumptionData(mPowerStatsInternal);
         }
 
         final List<Integer> energyConsumerIds = new ArrayList<>();
@@ -710,10 +797,8 @@
         if (energyConsumerIds.isEmpty()) {
             return null;
         }
-        synchronized (mStats) {
-            // TODO: Query *specific* subsystems from HAL based on energyConsumerIds.toArray()
-            return mStats.getEnergyConsumptionDataLocked();
-        }
+        // TODO: Query *specific* subsystems from HAL based on energyConsumerIds.toArray()
+        return getEnergyConsumptionData(mPowerStatsInternal);
     }
 
     @GuardedBy("mWorkerLock")
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 2f7c523..405ee72 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -16,14 +16,11 @@
 
 package com.android.server.am;
 
-import android.annotation.Nullable;
 import android.bluetooth.BluetoothActivityEnergyInfo;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.hardware.power.stats.EnergyConsumerId;
-import android.hardware.power.stats.EnergyConsumerResult;
 import android.os.BatteryStats;
 import android.os.BatteryStatsInternal;
 import android.os.BatteryUsageStats;
@@ -65,9 +62,6 @@
 import com.android.internal.os.PowerProfile;
 import com.android.internal.os.RailStats;
 import com.android.internal.os.RpmStats;
-import com.android.internal.power.MeasuredEnergyArray;
-import com.android.internal.power.MeasuredEnergyArray.MeasuredEnergySubsystem;
-import com.android.internal.power.MeasuredEnergyStats;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.ParseUtils;
@@ -75,7 +69,6 @@
 import com.android.server.LocalServices;
 import com.android.server.Watchdog;
 import com.android.server.pm.UserManagerInternal;
-import com.android.server.powerstats.PowerStatsHALWrapper;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -126,8 +119,6 @@
     private CharBuffer mUtf16BufferStat = CharBuffer.allocate(MAX_LOW_POWER_STATS_SIZE);
     private static final int MAX_LOW_POWER_STATS_SIZE = 4096;
 
-    private final PowerStatsHALWrapper.IPowerStatsHALWrapper mPowerStatsHALWrapper;
-
     private final HandlerThread mHandlerThread;
     private final Handler mHandler;
     private final Object mLock = new Object();
@@ -199,43 +190,6 @@
         }
     }
 
-    @Override
-    public @Nullable MeasuredEnergyArray getEnergyConsumptionData() {
-        final EnergyConsumerResult[] results = mPowerStatsHALWrapper.getEnergyConsumed(new int[0]);
-        if (results == null) return null;
-        final int size = results.length;
-        final int[] subsystems = new int[size];
-        final long[] energyUJ = new long[size];
-
-        for (int i = 0; i < size; i++) {
-            final EnergyConsumerResult consumer = results[i];
-            final int subsystem;
-            switch (consumer.energyConsumerId) {
-                case EnergyConsumerId.DISPLAY:
-                    subsystem = MeasuredEnergyArray.SUBSYSTEM_DISPLAY;
-                    break;
-                default:
-                    continue;
-            }
-            subsystems[i] = subsystem;
-            energyUJ[i] = consumer.energyUWs;
-        }
-        return new MeasuredEnergyArray() {
-            @Override
-            public int getSubsystem(int index) {
-                return subsystems[index];
-            }
-            @Override
-            public long getEnergy(int index) {
-                return energyUJ[index];
-            }
-            @Override
-            public int size() {
-                return size;
-            }
-        };
-    }
-
     BatteryStatsService(Context context, File systemDir, Handler handler) {
         // BatteryStatsImpl expects the ActivityManagerService handler, so pass that one through.
         mContext = context;
@@ -253,14 +207,9 @@
         mHandlerThread.start();
         mHandler = new Handler(mHandlerThread.getLooper());
 
-        // TODO(b/173077356): Replace directly calling the HAL with PowerStatsService queries
-        mPowerStatsHALWrapper = PowerStatsHALWrapper.getPowerStatsHalImpl();
-
-        final MeasuredEnergyArray initialEnergies = getEnergyConsumptionData();
-        final boolean[] supportedBuckets = getSupportedEnergyBuckets(initialEnergies);
         mStats = new BatteryStatsImpl(systemDir, handler, this,
-                this, supportedBuckets, mUserManagerUserInfoProvider);
-        mWorker = new BatteryExternalStatsWorker(context, mStats, initialEnergies);
+                this, mUserManagerUserInfoProvider);
+        mWorker = new BatteryExternalStatsWorker(context, mStats);
         mStats.setExternalStatsSyncLocked(mWorker);
         mStats.setRadioScanningTimeoutLocked(mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_radioScanningTimeout) * 1000L);
@@ -268,30 +217,6 @@
         mBatteryUsageStatsProvider = new BatteryUsageStatsProvider(context, mStats);
     }
 
-    /**
-     * Map the {@link MeasuredEnergySubsystem}s in the given energyArray to their corresponding
-     * {@link MeasuredEnergyStats.EnergyBucket}s.
-     *
-     * @return array with true for index i if energy bucket i is supported.
-     */
-    private static @Nullable boolean[] getSupportedEnergyBuckets(MeasuredEnergyArray energyArray) {
-        if (energyArray == null) {
-            return null;
-        }
-        final boolean[] buckets = new boolean[MeasuredEnergyStats.NUMBER_ENERGY_BUCKETS];
-        final int size = energyArray.size();
-        for (int energyIdx = 0; energyIdx < size; energyIdx++) {
-            switch (energyArray.getSubsystem(energyIdx)) {
-                case MeasuredEnergyArray.SUBSYSTEM_DISPLAY:
-                    buckets[MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_ON] = true;
-                    buckets[MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_DOZE] = true;
-                    buckets[MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_OTHER] = true;
-                    break;
-            }
-        }
-        return buckets;
-    }
-
     public void publish() {
         LocalServices.addService(BatteryStatsInternal.class, new LocalService());
         ServiceManager.addService(BatteryStats.SERVICE_NAME, asBinder());
@@ -299,6 +224,7 @@
 
     public void systemServicesReady() {
         mStats.systemServicesReady(mContext);
+        mWorker.systemServicesReady();
         Watchdog.getInstance().addMonitor(this);
     }
 
@@ -2270,7 +2196,6 @@
                                 in.setDataPosition(0);
                                 BatteryStatsImpl checkinStats = new BatteryStatsImpl(
                                         null, mStats.mHandler, null, null,
-                                        null /* energy buckets not currently in checkin anyway */,
                                         mUserManagerUserInfoProvider);
                                 checkinStats.readSummaryFromParcel(in);
                                 in.recycle();
@@ -2311,7 +2236,6 @@
                                 in.setDataPosition(0);
                                 BatteryStatsImpl checkinStats = new BatteryStatsImpl(
                                         null, mStats.mHandler, null, null,
-                                        null /* energy buckets not currently in checkin anyway */,
                                         mUserManagerUserInfoProvider);
                                 checkinStats.readSummaryFromParcel(in);
                                 in.recycle();
diff --git a/services/core/java/com/android/server/am/CacheOomRanker.java b/services/core/java/com/android/server/am/CacheOomRanker.java
new file mode 100644
index 0000000..26cfd62
--- /dev/null
+++ b/services/core/java/com/android/server/am/CacheOomRanker.java
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import android.provider.DeviceConfig;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.concurrent.Executor;
+
+/**
+ * Class to re-rank a number of the least recently used processes before they
+ * are assigned oom adjust scores.
+ */
+public class CacheOomRanker {
+    @VisibleForTesting
+    static final String KEY_USE_OOM_RE_RANKING = "use_oom_re_ranking";
+    private static final boolean DEFAULT_USE_OOM_RE_RANKING = false;
+    @VisibleForTesting
+    static final String KEY_OOM_RE_RANKING_NUMBER_TO_RE_RANK = "oom_re_ranking_number_to_re_rank";
+    @VisibleForTesting static final int DEFAULT_OOM_RE_RANKING_NUMBER_TO_RE_RANK = 8;
+    @VisibleForTesting
+    static final String KEY_OOM_RE_RANKING_LRU_WEIGHT = "oom_re_ranking_lru_weight";
+    @VisibleForTesting static final float DEFAULT_OOM_RE_RANKING_LRU_WEIGHT = 0.35f;
+    @VisibleForTesting
+    static final String KEY_OOM_RE_RANKING_USES_WEIGHT = "oom_re_ranking_uses_weight";
+    @VisibleForTesting static final float DEFAULT_OOM_RE_RANKING_USES_WEIGHT = 0.5f;
+    @VisibleForTesting
+    static final String KEY_OOM_RE_RANKING_RSS_WEIGHT = "oom_re_ranking_rss_weight";
+    @VisibleForTesting static final float DEFAULT_OOM_RE_RANKING_RSS_WEIGHT = 0.15f;
+
+    private static final Comparator<RankedProcessRecord> SCORED_PROCESS_RECORD_COMPARATOR =
+            new ScoreComparator();
+    private static final Comparator<RankedProcessRecord> CACHE_USE_COMPARATOR =
+            new CacheUseComparator();
+    private static final Comparator<RankedProcessRecord> LAST_RSS_COMPARATOR =
+            new LastRssComparator();
+    private static final Comparator<RankedProcessRecord> LAST_ACTIVITY_TIME_COMPARATOR =
+            new LastActivityTimeComparator();
+
+    private final Object mPhenotypeFlagLock = new Object();
+
+    @GuardedBy("mPhenotypeFlagLock")
+    private boolean mUseOomReRanking = DEFAULT_USE_OOM_RE_RANKING;
+    // Weight to apply to the LRU ordering.
+    @GuardedBy("mPhenotypeFlagLock")
+    @VisibleForTesting float mLruWeight = DEFAULT_OOM_RE_RANKING_LRU_WEIGHT;
+    // Weight to apply to the ordering by number of times the process has been added to the cache.
+    @GuardedBy("mPhenotypeFlagLock")
+    @VisibleForTesting float mUsesWeight = DEFAULT_OOM_RE_RANKING_USES_WEIGHT;
+    // Weight to apply to the ordering by RSS used by the processes.
+    @GuardedBy("mPhenotypeFlagLock")
+    @VisibleForTesting float mRssWeight = DEFAULT_OOM_RE_RANKING_RSS_WEIGHT;
+
+    // Positions to replace in the lru list.
+    @GuardedBy("mPhenotypeFlagLock")
+    private int[] mLruPositions;
+    // Processes to re-rank
+    @GuardedBy("mPhenotypeFlagLock")
+    private RankedProcessRecord[] mScoredProcessRecords;
+
+    private final DeviceConfig.OnPropertiesChangedListener mOnFlagsChangedListener =
+            new DeviceConfig.OnPropertiesChangedListener() {
+                @Override
+                public void onPropertiesChanged(DeviceConfig.Properties properties) {
+                    synchronized (mPhenotypeFlagLock) {
+                        for (String name : properties.getKeyset()) {
+                            if (KEY_USE_OOM_RE_RANKING.equals(name)) {
+                                updateUseOomReranking();
+                            } else if (KEY_OOM_RE_RANKING_NUMBER_TO_RE_RANK.equals(name)) {
+                                updateNumberToReRank();
+                            } else if (KEY_OOM_RE_RANKING_LRU_WEIGHT.equals(name)) {
+                                updateLruWeight();
+                            } else if (KEY_OOM_RE_RANKING_USES_WEIGHT.equals(name)) {
+                                updateUsesWeight();
+                            } else if (KEY_OOM_RE_RANKING_RSS_WEIGHT.equals(name)) {
+                                updateRssWeight();
+                            }
+                        }
+                    }
+                }
+            };
+
+    /** Load settings from device config and register a listener for changes. */
+    public void init(Executor executor) {
+        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                executor, mOnFlagsChangedListener);
+        synchronized (mPhenotypeFlagLock) {
+            updateUseOomReranking();
+            updateNumberToReRank();
+            updateLruWeight();
+            updateUsesWeight();
+            updateRssWeight();
+        }
+    }
+
+    /**
+     * Returns whether oom re-ranking is enabled.
+     */
+    public boolean useOomReranking() {
+        synchronized (mPhenotypeFlagLock) {
+            return mUseOomReRanking;
+        }
+    }
+
+    @GuardedBy("mPhenotypeFlagLock")
+    private void updateUseOomReranking() {
+        mUseOomReRanking = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                KEY_USE_OOM_RE_RANKING, DEFAULT_USE_OOM_RE_RANKING);
+    }
+
+    @GuardedBy("mPhenotypeFlagLock")
+    private void updateNumberToReRank() {
+        int previousNumberToReRank = getNumberToReRank();
+        int numberToReRank = DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                KEY_OOM_RE_RANKING_NUMBER_TO_RE_RANK, DEFAULT_OOM_RE_RANKING_NUMBER_TO_RE_RANK);
+        if (previousNumberToReRank != numberToReRank) {
+            mScoredProcessRecords = new RankedProcessRecord[numberToReRank];
+            for (int i = 0; i < mScoredProcessRecords.length; ++i) {
+                mScoredProcessRecords[i] = new RankedProcessRecord();
+            }
+            mLruPositions = new int[numberToReRank];
+        }
+    }
+
+    @GuardedBy("mPhenotypeFlagLock")
+    @VisibleForTesting
+    int getNumberToReRank() {
+        return mScoredProcessRecords == null ? 0 : mScoredProcessRecords.length;
+    }
+
+    @GuardedBy("mPhenotypeFlagLock")
+    private void updateLruWeight() {
+        mLruWeight = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                KEY_OOM_RE_RANKING_LRU_WEIGHT, DEFAULT_OOM_RE_RANKING_LRU_WEIGHT);
+    }
+
+    @GuardedBy("mPhenotypeFlagLock")
+    private void updateUsesWeight() {
+        mUsesWeight = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                KEY_OOM_RE_RANKING_USES_WEIGHT, DEFAULT_OOM_RE_RANKING_USES_WEIGHT);
+    }
+
+    @GuardedBy("mPhenotypeFlagLock")
+    private void updateRssWeight() {
+        mRssWeight = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                KEY_OOM_RE_RANKING_RSS_WEIGHT, DEFAULT_OOM_RE_RANKING_RSS_WEIGHT);
+    }
+
+    /**
+     * Re-rank the cached processes in the lru list with a weighted ordering
+     * of lru, rss size and number of times the process has been put in the cache.
+     */
+    public void reRankLruCachedApps(ProcessList processList) {
+        float lruWeight;
+        float usesWeight;
+        float rssWeight;
+        int[] lruPositions;
+        RankedProcessRecord[] scoredProcessRecords;
+
+        ArrayList<ProcessRecord> lruList = processList.mLruProcesses;
+
+        synchronized (mPhenotypeFlagLock) {
+            lruWeight = mLruWeight;
+            usesWeight = mUsesWeight;
+            rssWeight = mRssWeight;
+            lruPositions = mLruPositions;
+            scoredProcessRecords = mScoredProcessRecords;
+        }
+
+        // Don't re-rank if the class hasn't been initialized with defaults.
+        if (lruPositions == null || scoredProcessRecords == null) {
+            return;
+        }
+
+        // Collect the least recently used processes to re-rank, only rank cached
+        // processes further down the list than mLruProcessServiceStart.
+        int cachedProcessPos = 0;
+        for (int i = 0; i < processList.mLruProcessServiceStart
+                && cachedProcessPos < scoredProcessRecords.length; ++i) {
+            ProcessRecord app = lruList.get(i);
+            // Processes that will be assigned a cached oom adj score.
+            if (!app.killedByAm && app.thread != null && app.curAdj
+                    >= ProcessList.UNKNOWN_ADJ) {
+                scoredProcessRecords[cachedProcessPos].proc = app;
+                scoredProcessRecords[cachedProcessPos].score = 0.0f;
+                lruPositions[cachedProcessPos] = i;
+                ++cachedProcessPos;
+            }
+        }
+
+        // TODO maybe ensure a certain number above this in the cache before re-ranking.
+        if (cachedProcessPos < scoredProcessRecords.length)  {
+            // Ignore we don't have enough processes to worry about re-ranking.
+            return;
+        }
+
+        // Add scores for each of the weighted features we want to rank based on.
+        if (lruWeight > 0.0f) {
+            // This doesn't use the LRU list ordering as after the first re-ranking
+            // that will no longer be lru.
+            Arrays.sort(scoredProcessRecords, LAST_ACTIVITY_TIME_COMPARATOR);
+            addToScore(scoredProcessRecords, lruWeight);
+        }
+        if (rssWeight > 0.0f) {
+            Arrays.sort(scoredProcessRecords, LAST_RSS_COMPARATOR);
+            addToScore(scoredProcessRecords, rssWeight);
+        }
+        if (usesWeight > 0.0f) {
+            Arrays.sort(scoredProcessRecords, CACHE_USE_COMPARATOR);
+            addToScore(scoredProcessRecords, usesWeight);
+        }
+
+        // Re-rank by the new combined score.
+        Arrays.sort(scoredProcessRecords, SCORED_PROCESS_RECORD_COMPARATOR);
+
+        if (ActivityManagerDebugConfig.DEBUG_OOM_ADJ) {
+            boolean printedHeader = false;
+            for (int i = 0; i < scoredProcessRecords.length; ++i) {
+                if (scoredProcessRecords[i].proc.pid != lruList.get(lruPositions[i]).pid) {
+                    if (!printedHeader) {
+                        Slog.i(OomAdjuster.TAG, "reRankLruCachedApps");
+                        printedHeader = true;
+                    }
+                    Slog.i(OomAdjuster.TAG, "  newPos=" + lruPositions[i] + " "
+                            + scoredProcessRecords[i].proc);
+                }
+            }
+        }
+
+        for (int i = 0; i < scoredProcessRecords.length; ++i) {
+            lruList.set(lruPositions[i], scoredProcessRecords[i].proc);
+            scoredProcessRecords[i].proc = null;
+        }
+    }
+
+    private static void addToScore(RankedProcessRecord[] scores, float weight) {
+        for (int i = 1; i < scores.length; ++i) {
+            scores[i].score += i * weight;
+        }
+    }
+
+    void dump(PrintWriter pw) {
+        pw.println("CacheOomRanker settings");
+        synchronized (mPhenotypeFlagLock) {
+            pw.println("  " + KEY_USE_OOM_RE_RANKING + "=" + mUseOomReRanking);
+            pw.println("  " + KEY_OOM_RE_RANKING_NUMBER_TO_RE_RANK + "=" + getNumberToReRank());
+            pw.println("  " + KEY_OOM_RE_RANKING_LRU_WEIGHT + "=" + mLruWeight);
+            pw.println("  " + KEY_OOM_RE_RANKING_USES_WEIGHT + "=" + mUsesWeight);
+            pw.println("  " + KEY_OOM_RE_RANKING_RSS_WEIGHT + "=" + mRssWeight);
+        }
+    }
+
+    private static class ScoreComparator implements Comparator<RankedProcessRecord> {
+        @Override
+        public int compare(RankedProcessRecord o1, RankedProcessRecord o2) {
+            return Float.compare(o1.score, o2.score);
+        }
+    }
+
+    private static class LastActivityTimeComparator implements Comparator<RankedProcessRecord> {
+        @Override
+        public int compare(RankedProcessRecord o1, RankedProcessRecord o2) {
+            return Long.compare(o1.proc.lastActivityTime, o2.proc.lastActivityTime);
+        }
+    }
+
+    private static class CacheUseComparator implements Comparator<RankedProcessRecord> {
+        @Override
+        public int compare(RankedProcessRecord o1, RankedProcessRecord o2) {
+            return Long.compare(o1.proc.getCacheOomRankerUseCount(),
+                    o2.proc.getCacheOomRankerUseCount());
+        }
+    }
+
+    private static class LastRssComparator implements Comparator<RankedProcessRecord> {
+        @Override
+        public int compare(RankedProcessRecord o1, RankedProcessRecord o2) {
+            // High RSS first to match least recently used.
+            return Long.compare(o2.proc.mLastRss, o1.proc.mLastRss);
+        }
+    }
+
+    private static class RankedProcessRecord {
+        public ProcessRecord proc;
+        public float score;
+    }
+}
diff --git a/services/core/java/com/android/server/am/FgsStartTempAllowList.java b/services/core/java/com/android/server/am/FgsStartTempAllowList.java
index 1f90393..3aca4cf 100644
--- a/services/core/java/com/android/server/am/FgsStartTempAllowList.java
+++ b/services/core/java/com/android/server/am/FgsStartTempAllowList.java
@@ -28,7 +28,7 @@
 final class FgsStartTempAllowList {
     private static final int MAX_SIZE = 100;
     /**
-     * The key is the UID, the value is expiration elapse time in ms of this temp-allowed UID.
+     * The key is the uid, the value is expiration elapse time in ms of this temp-allowed uid.
      */
     private final SparseLongArray mTempAllowListFgs = new SparseLongArray();
 
@@ -37,7 +37,8 @@
 
     void add(int uid, long duration) {
         if (duration <= 0) {
-            Slog.e(TAG_AM, "FgsStartTempAllowList bad duration:" + duration + " uid: " + uid);
+            Slog.e(TAG_AM, "FgsStartTempAllowList bad duration:" + duration + " uid: "
+                    + uid);
             return;
         }
         // The temp allowlist should be a short list with only a few entries in it.
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index e5d57df..de79315 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -72,6 +72,7 @@
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
 
 import android.app.ActivityManager;
+import android.app.ActivityThread;
 import android.app.ApplicationExitInfo;
 import android.app.usage.UsageEvents;
 import android.compat.annotation.ChangeId;
@@ -91,7 +92,6 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.Trace;
-import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.LongSparseArray;
@@ -119,7 +119,7 @@
  * All of the code required to compute proc states and oom_adj values.
  */
 public final class OomAdjuster {
-    private static final String TAG = "OomAdjuster";
+    static final String TAG = "OomAdjuster";
     static final String OOM_ADJ_REASON_METHOD = "updateOomAdj";
     static final String OOM_ADJ_REASON_NONE = OOM_ADJ_REASON_METHOD + "_meh";
     static final String OOM_ADJ_REASON_ACTIVITY = OOM_ADJ_REASON_METHOD + "_activityChange";
@@ -169,6 +169,12 @@
      */
     CachedAppOptimizer mCachedAppOptimizer;
 
+    /**
+     * Re-rank apps getting a cache oom adjustment from lru to weighted order
+     * based on weighted scores for LRU, PSS and cache use count.
+     */
+    CacheOomRanker mCacheOomRanker;
+
     ActivityManagerConstants mConstants;
 
     final long[] mTmpLong = new long[3];
@@ -331,6 +337,7 @@
         mLocalPowerManager = LocalServices.getService(PowerManagerInternal.class);
         mConstants = mService.mConstants;
         mCachedAppOptimizer = new CachedAppOptimizer(mService);
+        mCacheOomRanker = new CacheOomRanker();
 
         mProcessGroupHandler = new Handler(adjusterThread.getLooper(), msg -> {
             final int pid = msg.arg1;
@@ -361,6 +368,7 @@
 
     void initSettings() {
         mCachedAppOptimizer.init();
+        mCacheOomRanker.init(ActivityThread.currentApplication().getMainExecutor());
         if (mService.mConstants.KEEP_WARMING_SERVICES.size() > 0) {
             final IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
             mService.mContext.registerReceiverForAllUsers(new BroadcastReceiver() {
@@ -769,6 +777,9 @@
             }
         }
 
+        if (mCacheOomRanker.useOomReranking()) {
+            mCacheOomRanker.reRankLruCachedApps(mProcessList);
+        }
         assignCachedAdjIfNecessary(mProcessList.mLruProcesses);
 
         if (computeClients) { // There won't be cycles if we didn't compute clients above.
@@ -2719,11 +2730,11 @@
     }
 
     @GuardedBy("mService")
-    final void setAppIdTempWhitelistStateLocked(int appId, boolean onWhitelist) {
+    final void setAppIdTempWhitelistStateLocked(int uid, boolean onWhitelist) {
         boolean changed = false;
         for (int i = mActiveUids.size() - 1; i >= 0; i--) {
             final UidRecord uidRec = mActiveUids.valueAt(i);
-            if (UserHandle.getAppId(uidRec.uid) == appId && uidRec.curWhitelist != onWhitelist) {
+            if (uidRec.uid == uid && uidRec.curWhitelist != onWhitelist) {
                 uidRec.curWhitelist = onWhitelist;
                 changed = true;
             }
@@ -2775,6 +2786,11 @@
     }
 
     @GuardedBy("mService")
+    void dumpCacheOomRankerSettings(PrintWriter pw) {
+        mCacheOomRanker.dump(pw);
+    }
+
+    @GuardedBy("mService")
     void updateAppFreezeStateLocked(ProcessRecord app) {
         if (!mCachedAppOptimizer.useFreezer()) {
             return;
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index d4d0165..520a28b 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -360,6 +360,13 @@
     int mCachedProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
     int mCachedSchedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
 
+    // Approximates the usage count of the app, used for cache re-ranking by CacheOomRanker.
+    //
+    // Counts the number of times the process is re-added to the cache (i.e. setCached(false);
+    // setCached(true)). This over counts, as setCached is sometimes reset while remaining in the
+    // cache. However, this happens uniformly across processes, so ranking is not affected.
+    private int mCacheOomRankerUseCount;
+
     boolean mReachable; // Whether or not this process is reachable from given process
 
     long mKillTime; // The timestamp in uptime when this process was killed.
@@ -828,7 +835,12 @@
     }
 
     void setCached(boolean cached) {
-        mCached = cached;
+        if (mCached != cached) {
+            mCached = cached;
+            if (cached) {
+                ++mCacheOomRankerUseCount;
+            }
+        }
     }
 
     @Override
@@ -836,6 +848,10 @@
         return mCached;
     }
 
+    int getCacheOomRankerUseCount() {
+        return mCacheOomRankerUseCount;
+    }
+
     boolean hasActivities() {
         return mWindowProcessController.hasActivities();
     }
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index c04f6ff..d73de7c 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -628,19 +628,30 @@
                     Binder.getCallingUid(), Binder.getCallingPid(), userId);
         }
 
-        if (getUserInfo(userId).isManagedProfile()) {
+        final UserInfo userInfo = getUserInfo(userId);
+        if (userInfo.isProfile()) {
             UserInfo parent = mInjector.getUserManager().getProfileParent(userId);
             if (parent != null) {
-                final Intent profileUnlockedIntent = new Intent(
-                        Intent.ACTION_MANAGED_PROFILE_UNLOCKED);
-                profileUnlockedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(userId));
-                profileUnlockedIntent.addFlags(
-                        Intent.FLAG_RECEIVER_REGISTERED_ONLY
-                                | Intent.FLAG_RECEIVER_FOREGROUND);
-                mInjector.broadcastIntent(profileUnlockedIntent,
-                        null, null, 0, null, null, null, AppOpsManager.OP_NONE,
-                        null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
-                        Binder.getCallingPid(), parent.id);
+                // Send PROFILE_ACCESSIBLE broadcast to the parent user if a profile was unlocked
+                broadcastProfileAccessibleStateChanged(userId, parent.id,
+                        Intent.ACTION_PROFILE_ACCESSIBLE);
+
+                //TODO(b/175704931): send ACTION_MANAGED_PROFILE_AVAILABLE
+
+                // Also send MANAGED_PROFILE_UNLOCKED broadcast to the parent user
+                // if a managed profile was unlocked
+                if (userInfo.isManagedProfile()) {
+                    final Intent profileUnlockedIntent = new Intent(
+                            Intent.ACTION_MANAGED_PROFILE_UNLOCKED);
+                    profileUnlockedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(userId));
+                    profileUnlockedIntent.addFlags(
+                            Intent.FLAG_RECEIVER_REGISTERED_ONLY
+                                    | Intent.FLAG_RECEIVER_FOREGROUND);
+                    mInjector.broadcastIntent(profileUnlockedIntent,
+                            null, null, 0, null, null, null, AppOpsManager.OP_NONE,
+                            null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
+                            Binder.getCallingPid(), parent.id);
+                }
             }
         }
 
@@ -761,13 +772,44 @@
     int restartUser(final int userId, final boolean foreground) {
         return stopUser(userId, /* force= */ true, /* allowDelayedLocking= */ false,
                 /* stopUserCallback= */ null, new KeyEvictedCallback() {
-            @Override
-            public void keyEvicted(@UserIdInt int userId) {
-                // Post to the same handler that this callback is called from to ensure the user
-                // cleanup is complete before restarting.
-                mHandler.post(() -> UserController.this.startUser(userId, foreground));
-            }
-        });
+                    @Override
+                    public void keyEvicted(@UserIdInt int userId) {
+                        // Post to the same handler that this callback is called from to ensure
+                        // the user cleanup is complete before restarting.
+                        mHandler.post(() -> UserController.this.startUser(userId, foreground));
+                    }
+                });
+    }
+
+    /**
+     * Stops a user only if it's a profile, with a more relaxed permission requirement:
+     * {@link android.Manifest.permission#MANAGE_USERS} or
+     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}.
+     * To be called from ActivityManagerService.
+     * @param userId the id of the user to stop.
+     * @return true if the operation was successful.
+     */
+    boolean stopProfile(final @UserIdInt int userId) {
+        if (mInjector.checkCallingPermission(android.Manifest.permission.MANAGE_USERS)
+                == PackageManager.PERMISSION_DENIED && mInjector.checkCallingPermission(
+                android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+                == PackageManager.PERMISSION_DENIED) {
+            throw new SecurityException(
+                    "You either need MANAGE_USERS or INTERACT_ACROSS_USERS_FULL permission to "
+                            + "stop a profile");
+        }
+
+        final UserInfo userInfo = getUserInfo(userId);
+        if (userInfo == null || !userInfo.isProfile()) {
+            throw new IllegalArgumentException("User " + userId + " is not a profile");
+        }
+
+        enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, userId);
+        synchronized (mLock) {
+            return stopUsersLU(userId, /* force= */ true, /* allowDelayedLocking= */
+                    false, /* stopUserCallback= */ null, /* keyEvictedCallback= */ null)
+                    == ActivityManager.USER_OP_SUCCESS;
+        }
     }
 
     int stopUser(final int userId, final boolean force, boolean allowDelayedLocking,
@@ -1144,6 +1186,17 @@
                 null, null, 0, null, null, null, AppOpsManager.OP_NONE,
                 null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
                 Binder.getCallingPid(), UserHandle.USER_ALL);
+
+        // Send PROFILE_INACCESSIBLE broadcast if a profile was stopped
+        final UserInfo userInfo = getUserInfo(userId);
+        if (userInfo.isProfile()) {
+            UserInfo parent = mInjector.getUserManager().getProfileParent(userId);
+            if (parent != null) {
+                broadcastProfileAccessibleStateChanged(userId, parent.id,
+                        Intent.ACTION_PROFILE_INACCESSIBLE);
+                //TODO(b/175704931): send ACTION_MANAGED_PROFILE_UNAVAILABLE
+            }
+        }
     }
 
     /**
@@ -1208,6 +1261,37 @@
         }
     }
 
+    /**
+     * Starts a user only if it's a profile, with a more relaxed permission requirement:
+     * {@link android.Manifest.permission#MANAGE_USERS} or
+     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}.
+     * To be called from ActivityManagerService.
+     * @param userId the id of the user to start.
+     * @return true if the operation was successful.
+     */
+    boolean startProfile(final @UserIdInt int userId) {
+        if (mInjector.checkCallingPermission(android.Manifest.permission.MANAGE_USERS)
+                == PackageManager.PERMISSION_DENIED && mInjector.checkCallingPermission(
+                android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+                == PackageManager.PERMISSION_DENIED) {
+            throw new SecurityException(
+                    "You either need MANAGE_USERS or INTERACT_ACROSS_USERS_FULL permission to "
+                            + "start a profile");
+        }
+
+        final UserInfo userInfo = getUserInfo(userId);
+        if (userInfo == null || !userInfo.isProfile()) {
+            throw new IllegalArgumentException("User " + userId + " is not a profile");
+        }
+
+        if (!userInfo.isEnabled()) {
+            Slog.w(TAG, "Cannot start disabled profile #" + userId);
+            return false;
+        }
+
+        return startUserNoChecks(userId, /* foreground= */ false, /* unlockListener= */ null);
+    }
+
     boolean startUser(final @UserIdInt int userId, final boolean foreground) {
         return startUser(userId, foreground, null);
     }
@@ -1248,9 +1332,13 @@
             final @UserIdInt int userId,
             final boolean foreground,
             @Nullable IProgressListener unlockListener) {
-
         checkCallingPermission(INTERACT_ACROSS_USERS_FULL, "startUser");
 
+        return startUserNoChecks(userId, foreground, unlockListener);
+    }
+
+    private boolean startUserNoChecks(final @UserIdInt int userId, final boolean foreground,
+            @Nullable IProgressListener unlockListener) {
         TimingsTraceAndSlog t = new TimingsTraceAndSlog();
 
         t.traceBegin("startUser-" + userId + "-" + (foreground ? "fg" : "bg"));
@@ -1872,6 +1960,25 @@
         }
     }
 
+    /**
+     * Broadcasts to the parent user when a profile is started+unlocked/stopped.
+     * @param userId the id of the profile
+     * @param parentId the id of the parent user
+     * @param intentAction either ACTION_PROFILE_ACCESSIBLE or ACTION_PROFILE_INACCESSIBLE
+     */
+    private void broadcastProfileAccessibleStateChanged(@UserIdInt int userId,
+            @UserIdInt int parentId,
+            String intentAction) {
+        final Intent intent = new Intent(intentAction);
+        intent.putExtra(Intent.EXTRA_USER, UserHandle.of(userId));
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+                | Intent.FLAG_RECEIVER_FOREGROUND);
+        mInjector.broadcastIntent(intent, /* resolvedType= */ null, /* resultTo= */
+                null, /* resultCode= */ 0, /* resultData= */ null, /* resultExtras= */
+                null, /* requiredPermissions= */ null, AppOpsManager.OP_NONE, /* bOptions= */
+                null, /* ordered= */ false, /* sticky= */ false, MY_PID, SYSTEM_UID,
+                Binder.getCallingUid(), Binder.getCallingPid(), parentId);
+    }
 
     int handleIncomingUser(int callingPid, int callingUid, @UserIdInt int userId, boolean allowAll,
             int allowMode, String name, String callerPackage) {
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index 676fcd0..17fd32c 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -1488,7 +1488,7 @@
         private void writeHistoricalPackageOpsDLocked(@NonNull HistoricalPackageOps packageOps,
                 @NonNull TypedXmlSerializer serializer) throws IOException {
             serializer.startTag(null, TAG_PACKAGE);
-            serializer.attribute(null, ATTR_NAME, packageOps.getPackageName());
+            serializer.attributeInterned(null, ATTR_NAME, packageOps.getPackageName());
             final int numAttributions = packageOps.getAttributedOpsCount();
             for (int i = 0; i < numAttributions; i++) {
                 final AppOpsManager.AttributedHistoricalOps op = packageOps.getAttributedOpsAt(i);
diff --git a/services/core/java/com/android/server/biometrics/AuthSession.java b/services/core/java/com/android/server/biometrics/AuthSession.java
index e4d9052..52152ab 100644
--- a/services/core/java/com/android/server/biometrics/AuthSession.java
+++ b/services/core/java/com/android/server/biometrics/AuthSession.java
@@ -805,7 +805,7 @@
     @Override
     public String toString() {
         return "State: " + mState
-                + "\nisCrypto: " + isCrypto()
-                + "\nPreAuthInfo: " + mPreAuthInfo;
+                + ", isCrypto: " + isCrypto()
+                + ", PreAuthInfo: " + mPreAuthInfo;
     }
 }
diff --git a/services/core/java/com/android/server/biometrics/BiometricSensor.java b/services/core/java/com/android/server/biometrics/BiometricSensor.java
index 17ec112..85de81bb3 100644
--- a/services/core/java/com/android/server/biometrics/BiometricSensor.java
+++ b/services/core/java/com/android/server/biometrics/BiometricSensor.java
@@ -169,12 +169,11 @@
     @Override
     public String toString() {
         return "ID(" + id + ")"
-                + "\n oemStrength: " + oemStrength
-                + "\n updatedStrength: " + mUpdatedStrength
-                + "\n modality " + modality
-                + "\n state: " + mSensorState
-                + "\n cookie: " + mCookie
-                + "\n authenticator: " + impl
-                + "\n";
+                + ", oemStrength: " + oemStrength
+                + ", updatedStrength: " + mUpdatedStrength
+                + ", modality " + modality
+                + ", state: " + mSensorState
+                + ", cookie: " + mCookie
+                + ", authenticator: " + impl;
     }
 }
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index fd5ada0..3387049 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -252,12 +252,14 @@
         @NonNull private final IInvalidationCallback mClientCallback;
         @NonNull private final Set<Integer> mSensorsPendingInvalidation;
 
-        public static InvalidationTracker start(@NonNull ArrayList<BiometricSensor> sensors,
+        public static InvalidationTracker start(@NonNull Context context,
+                @NonNull ArrayList<BiometricSensor> sensors,
                 int userId, int fromSensorId, @NonNull IInvalidationCallback clientCallback) {
-            return new InvalidationTracker(sensors, userId, fromSensorId, clientCallback);
+            return new InvalidationTracker(context, sensors, userId, fromSensorId, clientCallback);
         }
 
-        private InvalidationTracker(@NonNull ArrayList<BiometricSensor> sensors, int userId,
+        private InvalidationTracker(@NonNull Context context,
+                @NonNull ArrayList<BiometricSensor> sensors, int userId,
                 int fromSensorId, @NonNull IInvalidationCallback clientCallback) {
             mClientCallback = clientCallback;
             mSensorsPendingInvalidation = new ArraySet<>();
@@ -271,6 +273,14 @@
                     continue;
                 }
 
+                try {
+                    if (!sensor.impl.hasEnrolledTemplates(userId, context.getOpPackageName())) {
+                        continue;
+                    }
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Remote Exception", e);
+                }
+
                 Slog.d(TAG, "Requesting authenticatorId invalidation for sensor: " + sensor.id);
 
                 synchronized (this) {
@@ -288,6 +298,17 @@
                     Slog.d(TAG, "RemoteException", e);
                 }
             }
+
+            synchronized (this) {
+                if (mSensorsPendingInvalidation.isEmpty()) {
+                    try {
+                        Slog.d(TAG, "No sensors require invalidation");
+                        mClientCallback.onCompleted();
+                    } catch (RemoteException e) {
+                        Slog.e(TAG, "Remote Exception", e);
+                    }
+                }
+            }
         }
 
         @VisibleForTesting
@@ -742,7 +763,7 @@
                 IInvalidationCallback callback) {
             checkInternalPermission();
 
-            InvalidationTracker.start(mSensors, userId, fromSensorId, callback);
+            InvalidationTracker.start(getContext(), mSensors, userId, fromSensorId, callback);
         }
 
         @Override // Binder call
diff --git a/services/core/java/com/android/server/biometrics/Utils.java b/services/core/java/com/android/server/biometrics/Utils.java
index fa50388..55ac248 100644
--- a/services/core/java/com/android/server/biometrics/Utils.java
+++ b/services/core/java/com/android/server/biometrics/Utils.java
@@ -408,7 +408,7 @@
         return hasPermission && keyguardPackage != null && keyguardPackage.equals(clientPackage);
     }
 
-    public static String getClientName(@Nullable BaseClientMonitor<?> client) {
+    public static String getClientName(@Nullable BaseClientMonitor client) {
         return client != null ? client.getClass().getSimpleName() : "null";
     }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
index c662df2..b3580fb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
@@ -29,10 +29,10 @@
 import android.util.Slog;
 
 /**
- * Abstract {@link BaseClientMonitor} subclass that operations eligible/interested in acquisition
+ * Abstract {@link HalClientMonitor} subclass that operations eligible/interested in acquisition
  * messages should extend.
  */
-public abstract class AcquisitionClient<T> extends BaseClientMonitor<T> implements Interruptable {
+public abstract class AcquisitionClient<T> extends HalClientMonitor<T> implements Interruptable {
 
     private static final String TAG = "Biometrics/AcquisitionClient";
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
index 7c9fe38..f3c37ef 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
@@ -31,7 +31,7 @@
  * the current client.  Subclasses are responsible for coordinating the interaction with
  * the biometric's HAL for the specific action (e.g. authenticate, enroll, enumerate, etc.).
  */
-public abstract class BaseClientMonitor<T> extends LoggableMonitor
+public abstract class BaseClientMonitor extends LoggableMonitor
         implements IBinder.DeathRecipient {
 
     private static final String TAG = "Biometrics/ClientMonitor";
@@ -50,7 +50,7 @@
          *
          * @param clientMonitor Reference of the ClientMonitor that is starting.
          */
-        default void onClientStarted(@NonNull BaseClientMonitor<?> clientMonitor) {}
+        default void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {}
 
         /**
          * Invoked when the ClientMonitor operation is complete. This abstracts away asynchronous
@@ -61,23 +61,11 @@
          * @param clientMonitor Reference of the ClientMonitor that finished.
          * @param success True if the operation completed successfully.
          */
-        default void onClientFinished(@NonNull BaseClientMonitor<?> clientMonitor,
-                boolean success) {}
-    }
-
-    /**
-     * Interface that allows ClientMonitor subclasses to retrieve a fresh instance to the HAL.
-     */
-    public interface LazyDaemon<T> {
-        /**
-         * @return A fresh instance to the biometric HAL
-         */
-        T getDaemon();
+        default void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) {}
     }
 
     protected final int mSequentialId;
     @NonNull private final Context mContext;
-    @NonNull protected final LazyDaemon<T> mLazyDaemon;
     private final int mTargetUserId;
     @NonNull private final String mOwner;
     private final int mSensorId; // sensorId as configured by the framework
@@ -93,7 +81,6 @@
 
     /**
      * @param context    system_server context
-     * @param lazyDaemon pointer for lazy retrieval of the HAL
      * @param token      a unique token for the client
      * @param listener   recipient of related events (e.g. authentication)
      * @param userId     target user id for operation
@@ -104,14 +91,13 @@
      * @param statsAction   One of {@link BiometricsProtoEnums} ACTION_* constants
      * @param statsClient   One of {@link BiometricsProtoEnums} CLIENT_* constants
      */
-    public BaseClientMonitor(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
+    public BaseClientMonitor(@NonNull Context context,
             @Nullable IBinder token, @Nullable ClientMonitorCallbackConverter listener, int userId,
             @NonNull String owner, int cookie, int sensorId, int statsModality, int statsAction,
             int statsClient) {
         super(statsModality, statsAction, statsClient);
         mSequentialId = sCount++;
         mContext = context;
-        mLazyDaemon = lazyDaemon;
         mToken = token;
         mListener = listener;
         mTargetUserId = userId;
@@ -133,15 +119,7 @@
     }
 
     /**
-     * Invoked if the scheduler is unable to start the ClientMonitor (for example the HAL is null).
-     * If such a problem is detected, the scheduler will not invoke
-     * {@link #start(Callback)}.
-     */
-    public abstract void unableToStart();
-
-    /**
-     * Starts the ClientMonitor's lifecycle. Invokes {@link #startHalOperation()} when internal book
-     * keeping is complete.
+     * Starts the ClientMonitor's lifecycle.
      * @param callback invoked when the operation is complete (succeeds, fails, etc)
      */
     public void start(@NonNull Callback callback) {
@@ -149,10 +127,6 @@
         mCallback.onClientStarted(this);
     }
 
-    /**
-     * Starts the HAL operation specific to the ClientMonitor subclass.
-     */
-    protected abstract void startHalOperation();
 
     public boolean isAlreadyDone() {
         return mAlreadyDone;
@@ -221,10 +195,6 @@
         return mSensorId;
     }
 
-    public T getFreshDaemon() {
-        return mLazyDaemon.getDaemon();
-    }
-
     @Override
     public String toString() {
         return "{[" + mSequentialId + "] "
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
index fecc6f0..aa7faf5 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -101,17 +101,34 @@
         @Retention(RetentionPolicy.SOURCE)
         @interface OperationState {}
 
-        @NonNull final BaseClientMonitor<?> mClientMonitor;
+        @NonNull final BaseClientMonitor mClientMonitor;
         @Nullable final BaseClientMonitor.Callback mClientCallback;
         @OperationState int mState;
 
-        Operation(@NonNull BaseClientMonitor<?> clientMonitor,
+        Operation(@NonNull BaseClientMonitor clientMonitor,
                 @Nullable BaseClientMonitor.Callback callback) {
             this.mClientMonitor = clientMonitor;
             this.mClientCallback = callback;
             mState = STATE_WAITING_IN_QUEUE;
         }
 
+        public boolean isHalOperation() {
+            return mClientMonitor instanceof HalClientMonitor<?>;
+        }
+
+        /**
+         * @return true if the operation requires the HAL, and the HAL is null.
+         */
+        public boolean isUnstartableHalOperation() {
+            if (isHalOperation()) {
+                final HalClientMonitor<?> client = (HalClientMonitor<?>) mClientMonitor;
+                if (client.getFreshDaemon() == null) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
         @Override
         public String toString() {
             return mClientMonitor + ", State: " + mState;
@@ -188,7 +205,7 @@
     // starting the next client).
     public class InternalCallback implements BaseClientMonitor.Callback {
         @Override
-        public void onClientStarted(@NonNull BaseClientMonitor<?> clientMonitor) {
+        public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
             Slog.d(getTag(), "[Started] " + clientMonitor);
             if (mCurrentOperation.mClientCallback != null) {
                 mCurrentOperation.mClientCallback.onClientStarted(clientMonitor);
@@ -196,7 +213,7 @@
         }
 
         @Override
-        public void onClientFinished(@NonNull BaseClientMonitor<?> clientMonitor, boolean success) {
+        public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) {
             mHandler.post(() -> {
                 if (mCurrentOperation == null) {
                     Slog.e(getTag(), "[Finishing] " + clientMonitor
@@ -276,7 +293,7 @@
         }
 
         mCurrentOperation = mPendingOperations.poll();
-        final BaseClientMonitor<?> currentClient = mCurrentOperation.mClientMonitor;
+        final BaseClientMonitor currentClient = mCurrentOperation.mClientMonitor;
 
         // If the operation at the front of the queue has been marked for cancellation, send
         // ERROR_CANCELED. No need to start this client.
@@ -305,7 +322,9 @@
         // to arrive at the head of the queue, before pinging it to start.
         final boolean shouldStartNow = currentClient.getCookie() == 0;
         if (shouldStartNow) {
-            if (mCurrentOperation.mClientMonitor.getFreshDaemon() == null) {
+            if (mCurrentOperation.isUnstartableHalOperation()) {
+                final HalClientMonitor<?> halClientMonitor =
+                        (HalClientMonitor<?>) mCurrentOperation.mClientMonitor;
                 // Note down current length of queue
                 final int pendingOperationsLength = mPendingOperations.size();
                 final Operation lastOperation = mPendingOperations.peekLast();
@@ -315,7 +334,7 @@
                 // For current operations, 1) unableToStart, which notifies the caller-side, then
                 // 2) notify operation's callback, to notify applicable system service that the
                 // operation failed.
-                mCurrentOperation.mClientMonitor.unableToStart();
+                halClientMonitor.unableToStart();
                 if (mCurrentOperation.mClientCallback != null) {
                     mCurrentOperation.mClientCallback.onClientFinished(
                             mCurrentOperation.mClientMonitor, false /* success */);
@@ -331,7 +350,9 @@
                                 + ", expected length: " + pendingOperationsLength);
                         break;
                     }
-                    operation.mClientMonitor.unableToStart();
+                    if (operation.isHalOperation()) {
+                        ((HalClientMonitor<?>) operation.mClientMonitor).unableToStart();
+                    }
                     if (operation.mClientCallback != null) {
                         operation.mClientCallback.onClientFinished(operation.mClientMonitor,
                                 false /* success */);
@@ -401,10 +422,12 @@
             return;
         }
 
-        if (mCurrentOperation.mClientMonitor.getFreshDaemon() == null) {
+        if (mCurrentOperation.isUnstartableHalOperation()) {
             Slog.e(getTag(), "[Unable To Start] Prepared client: " + mCurrentOperation);
             // This is BiometricPrompt trying to auth but something's wrong with the HAL.
-            mCurrentOperation.mClientMonitor.unableToStart();
+            final HalClientMonitor<?> halClientMonitor =
+                    (HalClientMonitor<?>) mCurrentOperation.mClientMonitor;
+            halClientMonitor.unableToStart();
             if (mCurrentOperation.mClientCallback != null) {
                 mCurrentOperation.mClientCallback.onClientFinished(mCurrentOperation.mClientMonitor,
                         false /* success */);
@@ -423,7 +446,7 @@
      *
      * @param clientMonitor operation to be scheduled
      */
-    public void scheduleClientMonitor(@NonNull BaseClientMonitor<?> clientMonitor) {
+    public void scheduleClientMonitor(@NonNull BaseClientMonitor clientMonitor) {
         scheduleClientMonitor(clientMonitor, null /* clientFinishCallback */);
     }
 
@@ -434,7 +457,7 @@
      * @param clientCallback optional callback, invoked when the client is finished, but
      *                             before it has been removed from the queue.
      */
-    public void scheduleClientMonitor(@NonNull BaseClientMonitor<?> clientMonitor,
+    public void scheduleClientMonitor(@NonNull BaseClientMonitor clientMonitor,
             @Nullable BaseClientMonitor.Callback clientCallback) {
         // Mark any interruptable pending clients as canceling. Once they reach the head of the
         // queue, the scheduler will send ERROR_CANCELED and skip the operation.
@@ -537,7 +560,7 @@
     /**
      * @return the current operation
      */
-    public BaseClientMonitor<?> getCurrentClient() {
+    public BaseClientMonitor getCurrentClient() {
         if (mCurrentOperation == null) {
             return null;
         }
diff --git a/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java
index 7f01fda..6a622c3 100644
--- a/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java
@@ -23,7 +23,7 @@
 import android.os.RemoteException;
 import android.util.Slog;
 
-public abstract class GenerateChallengeClient<T> extends BaseClientMonitor<T> {
+public abstract class GenerateChallengeClient<T> extends HalClientMonitor<T> {
 
     private static final String TAG = "GenerateChallengeClient";
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/HalClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/HalClientMonitor.java
new file mode 100644
index 0000000..63cd412
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/HalClientMonitor.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics.sensors;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.os.IBinder;
+
+/**
+ * Abstract {@link BaseClientMonitor} implementation that supports HAL operations.
+ * @param <T> HAL template
+ */
+public abstract class HalClientMonitor<T> extends BaseClientMonitor {
+    /**
+     * Interface that allows ClientMonitor subclasses to retrieve a fresh instance to the HAL.
+     */
+    public interface LazyDaemon<T> {
+        /**
+         * @return A fresh instance to the biometric HAL
+         */
+        T getDaemon();
+    }
+
+    /**
+     * Starts the HAL operation specific to the ClientMonitor subclass.
+     */
+    protected abstract void startHalOperation();
+
+    /**
+     * Invoked if the scheduler is unable to start the ClientMonitor (for example the HAL is null).
+     * If such a problem is detected, the scheduler will not invoke
+     * {@link #start(Callback)}.
+     */
+    public abstract void unableToStart();
+
+    @NonNull
+    protected final LazyDaemon<T> mLazyDaemon;
+
+    /**
+     * @param context    system_server context
+     * @param lazyDaemon pointer for lazy retrieval of the HAL
+     * @param token      a unique token for the client
+     * @param listener   recipient of related events (e.g. authentication)
+     * @param userId     target user id for operation
+     * @param owner      name of the client that owns this
+     * @param cookie     BiometricPrompt authentication cookie (to be moved into a subclass soon)
+     * @param sensorId   ID of the sensor that the operation should be requested of
+     * @param statsModality One of {@link BiometricsProtoEnums} MODALITY_* constants
+     * @param statsAction   One of {@link BiometricsProtoEnums} ACTION_* constants
+     * @param statsClient   One of {@link BiometricsProtoEnums} CLIENT_* constants
+     */
+    public HalClientMonitor(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
+            @Nullable IBinder token, @Nullable ClientMonitorCallbackConverter listener, int userId,
+            @NonNull String owner, int cookie, int sensorId, int statsModality, int statsAction,
+            int statsClient) {
+        super(context, token, listener, userId, owner, cookie, sensorId, statsModality,
+                statsAction, statsClient);
+        mLazyDaemon = lazyDaemon;
+    }
+
+    @Nullable
+    public T getFreshDaemon() {
+        return mLazyDaemon.getDaemon();
+    }
+}
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 edc7edc..8529e81 100644
--- a/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java
@@ -39,7 +39,7 @@
  * {@link #onRemoved(BiometricAuthenticator.Identifier, int)} returns true/
  */
 public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Identifier, T>
-        extends BaseClientMonitor<T> implements EnumerateConsumer, RemovalConsumer {
+        extends HalClientMonitor<T> implements EnumerateConsumer, RemovalConsumer {
 
     private static final String TAG = "Biometrics/InternalCleanupClient";
 
@@ -60,11 +60,11 @@
     private final BiometricUtils<S> mBiometricUtils;
     private final Map<Integer, Long> mAuthenticatorIds;
     private final List<S> mEnrolledList;
-    private BaseClientMonitor<T> mCurrentTask;
+    private BaseClientMonitor mCurrentTask;
 
     private final Callback mEnumerateCallback = new Callback() {
         @Override
-        public void onClientFinished(@NonNull BaseClientMonitor<?> clientMonitor, boolean success) {
+        public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) {
             final List<BiometricAuthenticator.Identifier> unknownHALTemplates =
                     ((InternalEnumerateClient<T>) mCurrentTask).getUnknownHALTemplates();
 
@@ -88,7 +88,7 @@
 
     private final Callback mRemoveCallback = new Callback() {
         @Override
-        public void onClientFinished(@NonNull BaseClientMonitor<?> clientMonitor, boolean success) {
+        public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) {
             mCallback.onClientFinished(InternalCleanupClient.this, success);
         }
     };
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 176e49c..2693f2f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java
@@ -31,7 +31,7 @@
 /**
  * Internal class to help clean up unknown templates in the HAL and Framework
  */
-public abstract class InternalEnumerateClient<T> extends BaseClientMonitor<T>
+public abstract class InternalEnumerateClient<T> extends HalClientMonitor<T>
         implements EnumerateConsumer {
 
     private static final String TAG = "Biometrics/InternalEnumerateClient";
diff --git a/services/core/java/com/android/server/biometrics/sensors/InvalidationClient.java b/services/core/java/com/android/server/biometrics/sensors/InvalidationClient.java
index 93728d0..630e5ea 100644
--- a/services/core/java/com/android/server/biometrics/sensors/InvalidationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/InvalidationClient.java
@@ -31,7 +31,7 @@
  * {@link InvalidationRequesterClient} for more info.
  */
 public abstract class InvalidationClient<S extends BiometricAuthenticator.Identifier, T>
-        extends BaseClientMonitor<T> {
+        extends HalClientMonitor<T> {
 
     private static final String TAG = "InvalidationClient";
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/InvalidationRequesterClient.java b/services/core/java/com/android/server/biometrics/sensors/InvalidationRequesterClient.java
index e16b2f8..c97003b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/InvalidationRequesterClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/InvalidationRequesterClient.java
@@ -55,8 +55,8 @@
  * switches, the framework can check if any sensor has the "invalidationInProgress" flag set. If so,
  * the framework should re-start the invalidation process described above.
  */
-public abstract class InvalidationRequesterClient<S extends BiometricAuthenticator.Identifier, T>
-        extends BaseClientMonitor<T> {
+public class InvalidationRequesterClient<S extends BiometricAuthenticator.Identifier>
+        extends BaseClientMonitor {
 
     private final BiometricManager mBiometricManager;
     @NonNull private final BiometricUtils<S> mUtils;
@@ -71,9 +71,9 @@
         }
     };
 
-    public InvalidationRequesterClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
-            int userId, int sensorId, @NonNull BiometricUtils<S> utils) {
-        super(context, lazyDaemon, null /* token */, null /* listener */, userId,
+    public InvalidationRequesterClient(@NonNull Context context, int userId, int sensorId,
+            @NonNull BiometricUtils<S> utils) {
+        super(context, null /* token */, null /* listener */, userId,
                 context.getOpPackageName(), 0 /* cookie */, sensorId,
                 BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN,
                 BiometricsProtoEnums.CLIENT_UNKNOWN);
@@ -89,14 +89,4 @@
         mBiometricManager.invalidateAuthenticatorIds(getTargetUserId(), getSensorId(),
                 mInvalidationCallback);
     }
-
-    @Override
-    public void unableToStart() {
-
-    }
-
-    @Override
-    protected void startHalOperation() {
-        // No HAL operations necessary
-    }
 }
diff --git a/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java b/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java
index cec6dde..4ea48fd 100644
--- a/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java
@@ -31,7 +31,7 @@
  * A class to keep track of the remove state for a given client.
  */
 public abstract class RemovalClient<S extends BiometricAuthenticator.Identifier, T>
-        extends BaseClientMonitor<T> implements RemovalConsumer {
+        extends HalClientMonitor<T> implements RemovalConsumer {
 
     private static final String TAG = "Biometrics/RemovalClient";
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java
index 35cbcc0..187193d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java
@@ -21,7 +21,7 @@
 import android.hardware.biometrics.BiometricsProtoEnums;
 import android.os.IBinder;
 
-public abstract class RevokeChallengeClient<T> extends BaseClientMonitor<T> {
+public abstract class RevokeChallengeClient<T> extends HalClientMonitor<T> {
 
     public RevokeChallengeClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
             @NonNull IBinder token, @NonNull String owner, int sensorId) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java
index acf0f08..5fb194c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java
@@ -23,11 +23,11 @@
 import android.os.RemoteException;
 import android.util.Slog;
 
-import com.android.server.biometrics.sensors.BaseClientMonitor;
+import com.android.server.biometrics.sensors.HalClientMonitor;
 
 import java.util.Map;
 
-class FaceGetAuthenticatorIdClient extends BaseClientMonitor<ISession> {
+class FaceGetAuthenticatorIdClient extends HalClientMonitor<ISession> {
 
     private static final String TAG = "FaceGetAuthenticatorIdClient";
 
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 058bcf6..810489b1c 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
@@ -46,6 +46,8 @@
 import com.android.server.biometrics.sensors.AuthenticationClient;
 import com.android.server.biometrics.sensors.BaseClientMonitor;
 import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.HalClientMonitor;
+import com.android.server.biometrics.sensors.InvalidationRequesterClient;
 import com.android.server.biometrics.sensors.LockoutResetDispatcher;
 import com.android.server.biometrics.sensors.PerformanceTracker;
 import com.android.server.biometrics.sensors.face.FaceUtils;
@@ -73,7 +75,7 @@
     @NonNull private final String mHalInstanceName;
     @NonNull @VisibleForTesting
     final SparseArray<Sensor> mSensors; // Map of sensors that this HAL supports
-    @NonNull private final BaseClientMonitor.LazyDaemon<IFace> mLazyDaemon;
+    @NonNull private final HalClientMonitor.LazyDaemon<IFace> mLazyDaemon;
     @NonNull private final Handler mHandler;
     @NonNull private final LockoutResetDispatcher mLockoutResetDispatcher;
     @NonNull private final UsageStats mUsageStats;
@@ -87,7 +89,7 @@
         public void onTaskStackChanged() {
             mHandler.post(() -> {
                 for (int i = 0; i < mSensors.size(); i++) {
-                    final BaseClientMonitor<?> client = mSensors.valueAt(i).getScheduler()
+                    final BaseClientMonitor client = mSensors.valueAt(i).getScheduler()
                             .getCurrentClient();
                     if (!(client instanceof AuthenticationClient)) {
                         Slog.e(getTag(), "Task stack changed for client: " + client);
@@ -181,7 +183,7 @@
         return mDaemon;
     }
 
-    private void scheduleForSensor(int sensorId, @NonNull BaseClientMonitor<?> client) {
+    private void scheduleForSensor(int sensorId, @NonNull BaseClientMonitor client) {
         if (!mSensors.contains(sensorId)) {
             throw new IllegalStateException("Unable to schedule client: " + client
                     + " for sensor: " + sensorId);
@@ -189,7 +191,7 @@
         mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
     }
 
-    private void scheduleForSensor(int sensorId, @NonNull BaseClientMonitor<?> client,
+    private void scheduleForSensor(int sensorId, @NonNull BaseClientMonitor client,
             BaseClientMonitor.Callback callback) {
         if (!mSensors.contains(sensorId)) {
             throw new IllegalStateException("Unable to schedule client: " + client
@@ -205,6 +207,12 @@
         // this method "withoutHandler" means it should only ever be invoked from the worker thread,
         // so callers will never be blocked.
         mSensors.get(sensorId).createNewSession(daemon, sensorId, userId);
+
+        if (FaceUtils.getInstance(sensorId).isInvalidationInProgress(mContext, userId)) {
+            Slog.w(getTag(), "Scheduling unfinished invalidation request for sensor: " + sensorId
+                    + ", user: " + userId);
+            scheduleInvalidationRequest(sensorId, userId);
+        }
     }
 
 
@@ -241,6 +249,15 @@
         });
     }
 
+    private void scheduleInvalidationRequest(int sensorId, int userId) {
+        mHandler.post(() -> {
+            final InvalidationRequesterClient<Face> client =
+                    new InvalidationRequesterClient<>(mContext, userId, sensorId,
+                            FaceUtils.getInstance(sensorId));
+            mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
+        });
+    }
+
     @Override
     public boolean containsSensor(int sensorId) {
         return mSensors.contains(sensorId);
@@ -390,10 +407,11 @@
                         ENROLL_TIMEOUT_SEC, previewSurface, sensorId, maxTemplatesPerUser);
                 scheduleForSensor(sensorId, client, new BaseClientMonitor.Callback() {
                     @Override
-                    public void onClientFinished(@NonNull BaseClientMonitor<?> clientMonitor,
+                    public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
                             boolean success) {
                         if (success) {
                             scheduleLoadAuthenticatorIdsForUser(sensorId, userId);
+                            scheduleInvalidationRequest(sensorId, userId);
                         }
                     }
                 });
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java
index 7edeb7b..f355158 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java
@@ -26,7 +26,7 @@
 import android.util.Slog;
 
 import com.android.server.biometrics.HardwareAuthTokenUtils;
-import com.android.server.biometrics.sensors.BaseClientMonitor;
+import com.android.server.biometrics.sensors.HalClientMonitor;
 import com.android.server.biometrics.sensors.LockoutCache;
 import com.android.server.biometrics.sensors.LockoutResetDispatcher;
 import com.android.server.biometrics.sensors.LockoutTracker;
@@ -36,7 +36,7 @@
  * Updates the framework's lockout cache and notifies clients such as Keyguard when lockout is
  * cleared.
  */
-public class FaceResetLockoutClient extends BaseClientMonitor<ISession> {
+public class FaceResetLockoutClient extends HalClientMonitor<ISession> {
 
     private static final String TAG = "FaceResetLockoutClient";
 
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 90df726..82ad387 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
@@ -48,6 +48,7 @@
 import com.android.server.biometrics.sensors.BaseClientMonitor;
 import com.android.server.biometrics.sensors.BiometricScheduler;
 import com.android.server.biometrics.sensors.EnumerateConsumer;
+import com.android.server.biometrics.sensors.HalClientMonitor;
 import com.android.server.biometrics.sensors.Interruptable;
 import com.android.server.biometrics.sensors.LockoutCache;
 import com.android.server.biometrics.sensors.LockoutConsumer;
@@ -73,7 +74,7 @@
     @NonNull private final BiometricScheduler mScheduler;
     @NonNull private final LockoutCache mLockoutCache;
     @NonNull private final Map<Integer, Long> mAuthenticatorIds;
-    @NonNull private final BaseClientMonitor.LazyDaemon<ISession> mLazySession;
+    @NonNull private final HalClientMonitor.LazyDaemon<ISession> mLazySession;
     @Nullable private Session mCurrentSession;
 
     static class Session {
@@ -136,7 +137,7 @@
         @Override
         public void onChallengeGenerated(long challenge) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof FaceGenerateChallengeClient)) {
                     Slog.e(mTag, "onChallengeGenerated for wrong client: "
                             + Utils.getClientName(client));
@@ -152,7 +153,7 @@
         @Override
         public void onChallengeRevoked(long challenge) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof FaceRevokeChallengeClient)) {
                     Slog.e(mTag, "onChallengeRevoked for wrong client: "
                             + Utils.getClientName(client));
@@ -168,7 +169,7 @@
         @Override
         public void onAcquired(byte info, int vendorCode) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof AcquisitionClient)) {
                     Slog.e(mTag, "onAcquired for non-acquisition client: "
                             + Utils.getClientName(client));
@@ -183,7 +184,7 @@
         @Override
         public void onError(byte error, int vendorCode) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 Slog.d(mTag, "onError"
                         + ", client: " + Utils.getClientName(client)
                         + ", error: " + error
@@ -206,7 +207,7 @@
         @Override
         public void onEnrollmentProgress(int enrollmentId, int remaining) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof FaceEnrollClient)) {
                     Slog.e(mTag, "onEnrollmentProgress for non-enroll client: "
                             + Utils.getClientName(client));
@@ -226,7 +227,7 @@
         @Override
         public void onAuthenticationSucceeded(int enrollmentId, HardwareAuthToken hat) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof AuthenticationConsumer)) {
                     Slog.e(mTag, "onAuthenticationSucceeded for non-authentication consumer: "
                             + Utils.getClientName(client));
@@ -248,7 +249,7 @@
         @Override
         public void onAuthenticationFailed() {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof AuthenticationConsumer)) {
                     Slog.e(mTag, "onAuthenticationFailed for non-authentication consumer: "
                             + Utils.getClientName(client));
@@ -266,7 +267,7 @@
         @Override
         public void onLockoutTimed(long durationMillis) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof LockoutConsumer)) {
                     Slog.e(mTag, "onLockoutTimed for non-lockout consumer: "
                             + Utils.getClientName(client));
@@ -281,7 +282,7 @@
         @Override
         public void onLockoutPermanent() {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof LockoutConsumer)) {
                     Slog.e(mTag, "onLockoutPermanent for non-lockout consumer: "
                             + Utils.getClientName(client));
@@ -296,7 +297,7 @@
         @Override
         public void onLockoutCleared() {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof FaceResetLockoutClient)) {
                     Slog.e(mTag, "onLockoutCleared for non-resetLockout client: "
                             + Utils.getClientName(client));
@@ -316,7 +317,7 @@
         @Override
         public void onEnrollmentsEnumerated(int[] enrollmentIds) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof EnumerateConsumer)) {
                     Slog.e(mTag, "onEnrollmentsEnumerated for non-enumerate consumer: "
                             + Utils.getClientName(client));
@@ -339,7 +340,7 @@
         @Override
         public void onEnrollmentsRemoved(int[] enrollmentIds) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof RemovalConsumer)) {
                     Slog.e(mTag, "onRemoved for non-removal consumer: "
                             + Utils.getClientName(client));
@@ -361,7 +362,7 @@
         @Override
         public void onAuthenticatorIdRetrieved(long authenticatorId) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof FaceGetAuthenticatorIdClient)) {
                     Slog.e(mTag, "onAuthenticatorIdRetrieved for wrong consumer: "
                             + Utils.getClientName(client));
@@ -377,7 +378,7 @@
         @Override
         public void onAuthenticatorIdInvalidated(long newAuthenticatorId) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof FaceInvalidationClient)) {
                     Slog.e(mTag, "onAuthenticatorIdInvalidated for wrong consumer: "
                             + Utils.getClientName(client));
@@ -410,7 +411,7 @@
         };
     }
 
-    @NonNull BaseClientMonitor.LazyDaemon<ISession> getLazySession() {
+    @NonNull HalClientMonitor.LazyDaemon<ISession> getLazySession() {
         return mLazySession;
     }
 
@@ -491,7 +492,7 @@
     public void binderDied() {
         Slog.e(mTag, "Binder died");
         mHandler.post(() -> {
-            final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+            final BaseClientMonitor client = mScheduler.getCurrentClient();
             if (client instanceof Interruptable) {
                 Slog.e(mTag, "Sending ERROR_HW_UNAVAILABLE for client: " + client);
                 final Interruptable interruptable = (Interruptable) client;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestSession.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestSession.java
index fbc26c6..50483d9 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestSession.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestSession.java
@@ -24,12 +24,13 @@
 import android.hardware.keymaster.HardwareAuthToken;
 import android.os.Binder;
 import android.os.IBinder;
+import android.util.Slog;
 
 /**
  * Test session that provides mostly no-ops.
  */
 public class TestSession extends ISession.Stub {
-    private static final String TAG = "TestSession";
+    private static final String TAG = "FaceTestSession";
 
     @NonNull
     private final Sensor.HalSessionCallback mHalSessionCallback;
@@ -86,12 +87,16 @@
 
     @Override
     public void getAuthenticatorId(int cookie) {
+        Slog.d(TAG, "getAuthenticatorId");
+        // Immediately return a value so the framework can continue with subsequent requests.
         mHalSessionCallback.onAuthenticatorIdRetrieved(0);
     }
 
     @Override
     public void invalidateAuthenticatorId(int cookie) {
-
+        Slog.d(TAG, "invalidateAuthenticatorId");
+        // Immediately return a value so the framework can continue with subsequent requests.
+        mHalSessionCallback.onAuthenticatorIdInvalidated(0);
     }
 
     @Override
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 8593836..5e7ddeb 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
@@ -62,6 +62,7 @@
 import com.android.server.biometrics.sensors.BiometricScheduler;
 import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
 import com.android.server.biometrics.sensors.EnumerateConsumer;
+import com.android.server.biometrics.sensors.HalClientMonitor;
 import com.android.server.biometrics.sensors.Interruptable;
 import com.android.server.biometrics.sensors.LockoutResetDispatcher;
 import com.android.server.biometrics.sensors.LockoutTracker;
@@ -103,7 +104,7 @@
     @NonNull private final Context mContext;
     @NonNull private final BiometricScheduler mScheduler;
     @NonNull private final Handler mHandler;
-    @NonNull private final BaseClientMonitor.LazyDaemon<IBiometricsFace> mLazyDaemon;
+    @NonNull private final HalClientMonitor.LazyDaemon<IBiometricsFace> mLazyDaemon;
     @NonNull private final LockoutResetDispatcher mLockoutResetDispatcher;
     @NonNull private final LockoutHalImpl mLockoutTracker;
     @NonNull private final UsageStats mUsageStats;
@@ -170,7 +171,7 @@
                         .getUniqueName(mContext, userId);
                 final Face face = new Face(name, faceId, deviceId);
 
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof FaceEnrollClient)) {
                     Slog.e(TAG, "onEnrollResult for non-enroll client: "
                             + Utils.getClientName(client));
@@ -186,7 +187,7 @@
         public void onAuthenticated(long deviceId, int faceId, int userId,
                 ArrayList<Byte> token) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof AuthenticationConsumer)) {
                     Slog.e(TAG, "onAuthenticated for non-authentication consumer: "
                             + Utils.getClientName(client));
@@ -205,7 +206,7 @@
         public void onAcquired(long deviceId, int userId, int acquiredInfo,
                 int vendorCode) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof AcquisitionClient)) {
                     Slog.e(TAG, "onAcquired for non-acquire client: "
                             + Utils.getClientName(client));
@@ -221,7 +222,7 @@
         @Override
         public void onError(long deviceId, int userId, int error, int vendorCode) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 Slog.d(TAG, "handleError"
                         + ", client: " + (client != null ? client.getOwnerString() : null)
                         + ", error: " + error
@@ -247,7 +248,7 @@
         @Override
         public void onRemoved(long deviceId, ArrayList<Integer> removed, int userId) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof RemovalConsumer)) {
                     Slog.e(TAG, "onRemoved for non-removal consumer: "
                             + Utils.getClientName(client));
@@ -278,7 +279,7 @@
         @Override
         public void onEnumerate(long deviceId, ArrayList<Integer> faceIds, int userId) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof EnumerateConsumer)) {
                     Slog.e(TAG, "onEnumerate for non-enumerate consumer: "
                             + Utils.getClientName(client));
@@ -376,7 +377,7 @@
             mDaemon = null;
             mCurrentUserId = UserHandle.USER_NULL;
 
-            final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+            final BaseClientMonitor client = mScheduler.getCurrentClient();
             if (client instanceof Interruptable) {
                 Slog.e(TAG, "Sending ERROR_HW_UNAVAILABLE for client: " + client);
                 final Interruptable interruptable = (Interruptable) client;
@@ -482,7 +483,7 @@
 
     @Override
     public long getAuthenticatorId(int sensorId, int userId) {
-        return mAuthenticatorIds.get(userId);
+        return mAuthenticatorIds.getOrDefault(userId, 0L);
     }
 
     @Override
@@ -530,7 +531,7 @@
                     mSensorId, mCurrentChallengeOwner);
             mScheduler.scheduleClientMonitor(client, new BaseClientMonitor.Callback() {
                 @Override
-                public void onClientStarted(@NonNull BaseClientMonitor<?> clientMonitor) {
+                public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
                     if (client != clientMonitor) {
                         Slog.e(TAG, "scheduleGenerateChallenge onClientStarted, mismatched client."
                                 + " Expecting: " + client + ", received: " + clientMonitor);
@@ -559,7 +560,7 @@
                     mLazyDaemon, token, opPackageName, mSensorId);
             mScheduler.scheduleClientMonitor(client, new BaseClientMonitor.Callback() {
                 @Override
-                public void onClientFinished(@NonNull BaseClientMonitor<?> clientMonitor,
+                public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
                         boolean success) {
                     if (client != clientMonitor) {
                         Slog.e(TAG, "scheduleRevokeChallenge, mismatched client."
@@ -615,7 +616,7 @@
 
             mScheduler.scheduleClientMonitor(client, new BaseClientMonitor.Callback() {
                 @Override
-                public void onClientFinished(@NonNull BaseClientMonitor<?> clientMonitor,
+                public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
                         boolean success) {
                     if (success) {
                         // Update authenticatorIds
@@ -727,7 +728,7 @@
             mScheduler.scheduleClientMonitor(client, new BaseClientMonitor.Callback() {
                 @Override
                 public void onClientFinished(
-                        @NonNull BaseClientMonitor<?> clientMonitor, boolean success) {
+                        @NonNull BaseClientMonitor clientMonitor, boolean success) {
                     if (success && feature == BiometricFaceConstants.FEATURE_REQUIRE_ATTENTION) {
                         final int settingsValue = client.getValue() ? 1 : 0;
                         Slog.d(TAG, "Updating attention value for user: " + userId
@@ -864,7 +865,7 @@
                 hasEnrolled, mAuthenticatorIds);
         mScheduler.scheduleClientMonitor(client, new BaseClientMonitor.Callback() {
             @Override
-            public void onClientFinished(@NonNull BaseClientMonitor<?> clientMonitor,
+            public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
                     boolean success) {
                 if (success) {
                     mCurrentUserId = targetUserId;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java
index d30c9b1..442303b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java
@@ -27,14 +27,14 @@
 import android.os.RemoteException;
 import android.util.Slog;
 
-import com.android.server.biometrics.sensors.BaseClientMonitor;
 import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.HalClientMonitor;
 
 /**
  * Face-specific getFeature client supporting the {@link android.hardware.biometrics.face.V1_0}
  * and {@link android.hardware.biometrics.face.V1_1} HIDL interfaces.
  */
-public class FaceGetFeatureClient extends BaseClientMonitor<IBiometricsFace> {
+public class FaceGetFeatureClient extends HalClientMonitor<IBiometricsFace> {
 
     private static final String TAG = "FaceGetFeatureClient";
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceResetLockoutClient.java
index bb83860..e0548e0 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceResetLockoutClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceResetLockoutClient.java
@@ -23,7 +23,7 @@
 import android.os.RemoteException;
 import android.util.Slog;
 
-import com.android.server.biometrics.sensors.BaseClientMonitor;
+import com.android.server.biometrics.sensors.HalClientMonitor;
 
 import java.util.ArrayList;
 
@@ -31,7 +31,7 @@
  * Face-specific resetLockout client supporting the {@link android.hardware.biometrics.face.V1_0}
  * and {@link android.hardware.biometrics.face.V1_1} HIDL interfaces.
  */
-public class FaceResetLockoutClient extends BaseClientMonitor<IBiometricsFace> {
+public class FaceResetLockoutClient extends HalClientMonitor<IBiometricsFace> {
 
     private static final String TAG = "FaceResetLockoutClient";
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceSetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceSetFeatureClient.java
index 0fb0de2..4356043 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceSetFeatureClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceSetFeatureClient.java
@@ -25,8 +25,8 @@
 import android.os.RemoteException;
 import android.util.Slog;
 
-import com.android.server.biometrics.sensors.BaseClientMonitor;
 import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.HalClientMonitor;
 
 import java.util.ArrayList;
 
@@ -34,7 +34,7 @@
  * Face-specific setFeature client supporting the {@link android.hardware.biometrics.face.V1_0}
  * and {@link android.hardware.biometrics.face.V1_1} HIDL interfaces.
  */
-public class FaceSetFeatureClient extends BaseClientMonitor<IBiometricsFace> {
+public class FaceSetFeatureClient extends HalClientMonitor<IBiometricsFace> {
 
     private static final String TAG = "FaceSetFeatureClient";
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java
index 78ee714..0e72f94 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java
@@ -24,12 +24,12 @@
 import android.os.RemoteException;
 import android.util.Slog;
 
-import com.android.server.biometrics.sensors.BaseClientMonitor;
+import com.android.server.biometrics.sensors.HalClientMonitor;
 
 import java.io.File;
 import java.util.Map;
 
-public class FaceUpdateActiveUserClient extends BaseClientMonitor<IBiometricsFace> {
+public class FaceUpdateActiveUserClient extends HalClientMonitor<IBiometricsFace> {
     private static final String TAG = "FaceUpdateActiveUserClient";
     private static final String FACE_DATA_DIR = "facedata";
 
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 82dc161..c413c8b 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
@@ -79,6 +79,13 @@
     }
 
     @Override
+    public void onError(int errorCode, int vendorCode) {
+        super.onError(errorCode, vendorCode);
+
+        UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
+    }
+
+    @Override
     protected void startHalOperation() {
         UdfpsHelper.showUdfpsOverlay(getSensorId(), IUdfpsOverlayController.REASON_AUTH,
                 mUdfpsOverlayController);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
index cacc366..0864c1a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
@@ -71,6 +71,13 @@
     }
 
     @Override
+    public void onError(int errorCode, int vendorCode) {
+        super.onError(errorCode, vendorCode);
+
+        UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
+    }
+
+    @Override
     protected boolean hasReachedEnrollmentLimit() {
         return FingerprintUtils.getInstance(getSensorId())
                 .getBiometricsForUser(getContext(), getTargetUserId()).size()
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGetAuthenticatorIdClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGetAuthenticatorIdClient.java
index 8170041..02d4ac3 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGetAuthenticatorIdClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGetAuthenticatorIdClient.java
@@ -23,11 +23,11 @@
 import android.os.RemoteException;
 import android.util.Slog;
 
-import com.android.server.biometrics.sensors.BaseClientMonitor;
+import com.android.server.biometrics.sensors.HalClientMonitor;
 
 import java.util.Map;
 
-class FingerprintGetAuthenticatorIdClient extends BaseClientMonitor<ISession> {
+class FingerprintGetAuthenticatorIdClient extends HalClientMonitor<ISession> {
 
     private static final String TAG = "FingerprintGetAuthenticatorIdClient";
 
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 d65ecff..8a666f9 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
@@ -46,6 +46,8 @@
 import com.android.server.biometrics.sensors.AuthenticationClient;
 import com.android.server.biometrics.sensors.BaseClientMonitor;
 import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.HalClientMonitor;
+import com.android.server.biometrics.sensors.InvalidationRequesterClient;
 import com.android.server.biometrics.sensors.LockoutResetDispatcher;
 import com.android.server.biometrics.sensors.PerformanceTracker;
 import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
@@ -74,7 +76,7 @@
     @NonNull private final String mHalInstanceName;
     @NonNull @VisibleForTesting
     final SparseArray<Sensor> mSensors; // Map of sensors that this HAL supports
-    @NonNull private final BaseClientMonitor.LazyDaemon<IFingerprint> mLazyDaemon;
+    @NonNull private final HalClientMonitor.LazyDaemon<IFingerprint> mLazyDaemon;
     @NonNull private final Handler mHandler;
     @NonNull private final LockoutResetDispatcher mLockoutResetDispatcher;
     @NonNull private final ActivityTaskManager mActivityTaskManager;
@@ -88,7 +90,7 @@
         public void onTaskStackChanged() {
             mHandler.post(() -> {
                 for (int i = 0; i < mSensors.size(); i++) {
-                    final BaseClientMonitor<?> client = mSensors.valueAt(i).getScheduler()
+                    final BaseClientMonitor client = mSensors.valueAt(i).getScheduler()
                             .getCurrentClient();
                     if (!(client instanceof AuthenticationClient)) {
                         Slog.e(getTag(), "Task stack changed for client: " + client);
@@ -187,7 +189,7 @@
         return mDaemon;
     }
 
-    private void scheduleForSensor(int sensorId, @NonNull BaseClientMonitor<?> client) {
+    private void scheduleForSensor(int sensorId, @NonNull BaseClientMonitor client) {
         if (!mSensors.contains(sensorId)) {
             throw new IllegalStateException("Unable to schedule client: " + client
                     + " for sensor: " + sensorId);
@@ -195,7 +197,7 @@
         mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
     }
 
-    private void scheduleForSensor(int sensorId, @NonNull BaseClientMonitor<?> client,
+    private void scheduleForSensor(int sensorId, @NonNull BaseClientMonitor client,
             BaseClientMonitor.Callback callback) {
         if (!mSensors.contains(sensorId)) {
             throw new IllegalStateException("Unable to schedule client: " + client
@@ -211,6 +213,12 @@
         // this method "withoutHandler" means it should only ever be invoked from the worker thread,
         // so callers will never be blocked.
         mSensors.get(sensorId).createNewSession(daemon, sensorId, userId);
+
+        if (FingerprintUtils.getInstance(sensorId).isInvalidationInProgress(mContext, userId)) {
+            Slog.w(getTag(), "Scheduling unfinished invalidation request for sensor: " + sensorId
+                    + ", user: " + userId);
+            scheduleInvalidationRequest(sensorId, userId);
+        }
     }
 
     @Override
@@ -267,6 +275,15 @@
         });
     }
 
+    private void scheduleInvalidationRequest(int sensorId, int userId) {
+        mHandler.post(() -> {
+            final InvalidationRequesterClient<Fingerprint> client =
+                    new InvalidationRequesterClient<>(mContext, userId, sensorId,
+                            FingerprintUtils.getInstance(sensorId));
+            mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
+        });
+    }
+
     @Override
     public void scheduleResetLockout(int sensorId, int userId, @Nullable byte[] hardwareAuthToken) {
         mHandler.post(() -> {
@@ -373,10 +390,11 @@
                         mUdfpsOverlayController, maxTemplatesPerUser, shouldLogMetrics);
                 scheduleForSensor(sensorId, client, new BaseClientMonitor.Callback() {
                     @Override
-                    public void onClientFinished(@NonNull BaseClientMonitor<?> clientMonitor,
+                    public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
                             boolean success) {
                         if (success) {
                             scheduleLoadAuthenticatorIdsForUser(sensorId, userId);
+                            scheduleInvalidationRequest(sensorId, userId);
                         }
                     }
                 });
@@ -581,7 +599,7 @@
 
     @Override
     public void onPointerDown(int sensorId, int x, int y, float minor, float major) {
-        final BaseClientMonitor<?> client =
+        final BaseClientMonitor client =
                 mSensors.get(sensorId).getScheduler().getCurrentClient();
         if (!(client instanceof Udfps)) {
             Slog.e(getTag(), "onPointerDown received during client: " + client);
@@ -593,7 +611,7 @@
 
     @Override
     public void onPointerUp(int sensorId) {
-        final BaseClientMonitor<?> client =
+        final BaseClientMonitor client =
                 mSensors.get(sensorId).getScheduler().getCurrentClient();
         if (!(client instanceof Udfps)) {
             Slog.e(getTag(), "onPointerUp received during client: " + client);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
index 3bdcc1d..cd84cdf 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
@@ -26,7 +26,7 @@
 import android.util.Slog;
 
 import com.android.server.biometrics.HardwareAuthTokenUtils;
-import com.android.server.biometrics.sensors.BaseClientMonitor;
+import com.android.server.biometrics.sensors.HalClientMonitor;
 import com.android.server.biometrics.sensors.LockoutCache;
 import com.android.server.biometrics.sensors.LockoutResetDispatcher;
 import com.android.server.biometrics.sensors.LockoutTracker;
@@ -36,7 +36,7 @@
  * Updates the framework's lockout cache and notifies clients such as Keyguard when lockout is
  * cleared.
  */
-class FingerprintResetLockoutClient extends BaseClientMonitor<ISession> {
+class FingerprintResetLockoutClient extends HalClientMonitor<ISession> {
 
     private static final String TAG = "FingerprintResetLockoutClient";
 
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 c0f0577..911f6b4 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
@@ -48,6 +48,7 @@
 import com.android.server.biometrics.sensors.BaseClientMonitor;
 import com.android.server.biometrics.sensors.BiometricScheduler;
 import com.android.server.biometrics.sensors.EnumerateConsumer;
+import com.android.server.biometrics.sensors.HalClientMonitor;
 import com.android.server.biometrics.sensors.Interruptable;
 import com.android.server.biometrics.sensors.LockoutCache;
 import com.android.server.biometrics.sensors.LockoutConsumer;
@@ -78,7 +79,7 @@
     @NonNull private final Map<Integer, Long> mAuthenticatorIds;
 
     @Nullable private Session mCurrentSession;
-    @NonNull private final BaseClientMonitor.LazyDaemon<ISession> mLazySession;
+    @NonNull private final HalClientMonitor.LazyDaemon<ISession> mLazySession;
 
     static class Session {
         @NonNull private final String mTag;
@@ -136,7 +137,7 @@
         @Override
         public void onChallengeGenerated(long challenge) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof FingerprintGenerateChallengeClient)) {
                     Slog.e(mTag, "onChallengeGenerated for wrong client: "
                             + Utils.getClientName(client));
@@ -152,7 +153,7 @@
         @Override
         public void onChallengeRevoked(long challenge) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof FingerprintRevokeChallengeClient)) {
                     Slog.e(mTag, "onChallengeRevoked for wrong client: "
                             + Utils.getClientName(client));
@@ -168,7 +169,7 @@
         @Override
         public void onAcquired(byte info, int vendorCode) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof AcquisitionClient)) {
                     Slog.e(mTag, "onAcquired for non-acquisition client: "
                             + Utils.getClientName(client));
@@ -183,7 +184,7 @@
         @Override
         public void onError(byte error, int vendorCode) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 Slog.d(mTag, "onError"
                         + ", client: " + Utils.getClientName(client)
                         + ", error: " + error
@@ -206,7 +207,7 @@
         @Override
         public void onEnrollmentProgress(int enrollmentId, int remaining) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof FingerprintEnrollClient)) {
                     Slog.e(mTag, "onEnrollmentProgress for non-enroll client: "
                             + Utils.getClientName(client));
@@ -226,7 +227,7 @@
         @Override
         public void onAuthenticationSucceeded(int enrollmentId, HardwareAuthToken hat) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof AuthenticationConsumer)) {
                     Slog.e(mTag, "onAuthenticationSucceeded for non-authentication consumer: "
                             + Utils.getClientName(client));
@@ -249,7 +250,7 @@
         @Override
         public void onAuthenticationFailed() {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof AuthenticationConsumer)) {
                     Slog.e(mTag, "onAuthenticationFailed for non-authentication consumer: "
                             + Utils.getClientName(client));
@@ -267,7 +268,7 @@
         @Override
         public void onLockoutTimed(long durationMillis) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof LockoutConsumer)) {
                     Slog.e(mTag, "onLockoutTimed for non-lockout consumer: "
                             + Utils.getClientName(client));
@@ -282,7 +283,7 @@
         @Override
         public void onLockoutPermanent() {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof LockoutConsumer)) {
                     Slog.e(mTag, "onLockoutPermanent for non-lockout consumer: "
                             + Utils.getClientName(client));
@@ -297,7 +298,7 @@
         @Override
         public void onLockoutCleared() {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof FingerprintResetLockoutClient)) {
                     Slog.e(mTag, "onLockoutCleared for non-resetLockout client: "
                             + Utils.getClientName(client));
@@ -313,7 +314,7 @@
         @Override
         public void onInteractionDetected() {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof FingerprintDetectClient)) {
                     Slog.e(mTag, "onInteractionDetected for non-detect client: "
                             + Utils.getClientName(client));
@@ -329,7 +330,7 @@
         @Override
         public void onEnrollmentsEnumerated(int[] enrollmentIds) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof EnumerateConsumer)) {
                     Slog.e(mTag, "onEnrollmentsEnumerated for non-enumerate consumer: "
                             + Utils.getClientName(client));
@@ -352,7 +353,7 @@
         @Override
         public void onEnrollmentsRemoved(int[] enrollmentIds) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof RemovalConsumer)) {
                     Slog.e(mTag, "onRemoved for non-removal consumer: "
                             + Utils.getClientName(client));
@@ -374,7 +375,7 @@
         @Override
         public void onAuthenticatorIdRetrieved(long authenticatorId) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof FingerprintGetAuthenticatorIdClient)) {
                     Slog.e(mTag, "onAuthenticatorIdRetrieved for wrong consumer: "
                             + Utils.getClientName(client));
@@ -390,7 +391,7 @@
         @Override
         public void onAuthenticatorIdInvalidated(long newAuthenticatorId) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof FingerprintInvalidationClient)) {
                     Slog.e(mTag, "onAuthenticatorIdInvalidated for wrong consumer: "
                             + Utils.getClientName(client));
@@ -424,7 +425,7 @@
         };
     }
 
-    @NonNull BaseClientMonitor.LazyDaemon<ISession> getLazySession() {
+    @NonNull HalClientMonitor.LazyDaemon<ISession> getLazySession() {
         return mLazySession;
     }
 
@@ -505,7 +506,7 @@
     public void binderDied() {
         Slog.e(mTag, "Binder died");
         mHandler.post(() -> {
-            final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+            final BaseClientMonitor client = mScheduler.getCurrentClient();
             if (client instanceof Interruptable) {
                 Slog.e(mTag, "Sending ERROR_HW_UNAVAILABLE for client: " + client);
                 final Interruptable interruptable = (Interruptable) client;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestSession.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestSession.java
index ddae110..ac4f665 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestSession.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestSession.java
@@ -30,7 +30,7 @@
  */
 class TestSession extends ISession.Stub {
 
-    private static final String TAG = "TestSession";
+    private static final String TAG = "FingerprintTestSession";
 
     @NonNull private final Sensor.HalSessionCallback mHalSessionCallback;
 
@@ -92,7 +92,9 @@
 
     @Override
     public void invalidateAuthenticatorId(int cookie) {
-
+        Slog.d(TAG, "invalidateAuthenticatorId");
+        // Immediately return a value so the framework can continue with subsequent requests.
+        mHalSessionCallback.onAuthenticatorIdInvalidated(0);
     }
 
     @Override
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 e57e675..6cc8687 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
@@ -62,6 +62,7 @@
 import com.android.server.biometrics.sensors.BiometricScheduler;
 import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
 import com.android.server.biometrics.sensors.EnumerateConsumer;
+import com.android.server.biometrics.sensors.HalClientMonitor;
 import com.android.server.biometrics.sensors.Interruptable;
 import com.android.server.biometrics.sensors.LockoutResetDispatcher;
 import com.android.server.biometrics.sensors.LockoutTracker;
@@ -103,7 +104,7 @@
     private final LockoutResetDispatcher mLockoutResetDispatcher;
     private final LockoutFrameworkImpl mLockoutTracker;
     private final BiometricTaskStackListener mTaskStackListener;
-    private final BaseClientMonitor.LazyDaemon<IBiometricsFingerprint> mLazyDaemon;
+    private final HalClientMonitor.LazyDaemon<IBiometricsFingerprint> mLazyDaemon;
     private final Map<Integer, Long> mAuthenticatorIds;
 
     @Nullable private IBiometricsFingerprint mDaemon;
@@ -116,7 +117,7 @@
         @Override
         public void onTaskStackChanged() {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof AuthenticationClient)) {
                     Slog.e(TAG, "Task stack changed for client: " + client);
                     return;
@@ -188,7 +189,7 @@
         @Override
         public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof FingerprintEnrollClient)) {
                     Slog.e(TAG, "onEnrollResult for non-enroll client: "
                             + Utils.getClientName(client));
@@ -213,7 +214,7 @@
         @Override
         public void onAcquired_2_2(long deviceId, int acquiredInfo, int vendorCode) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof AcquisitionClient)) {
                     Slog.e(TAG, "onAcquired for non-acquisition client: "
                             + Utils.getClientName(client));
@@ -229,7 +230,7 @@
         public void onAuthenticated(long deviceId, int fingerId, int groupId,
                 ArrayList<Byte> token) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof AuthenticationConsumer)) {
                     Slog.e(TAG, "onAuthenticated for non-authentication consumer: "
                             + Utils.getClientName(client));
@@ -247,7 +248,7 @@
         @Override
         public void onError(long deviceId, int error, int vendorCode) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 Slog.d(TAG, "handleError"
                         + ", client: " + Utils.getClientName(client)
                         + ", error: " + error
@@ -273,7 +274,7 @@
         public void onRemoved(long deviceId, int fingerId, int groupId, int remaining) {
             mHandler.post(() -> {
                 Slog.d(TAG, "Removed, fingerId: " + fingerId + ", remaining: " + remaining);
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof RemovalConsumer)) {
                     Slog.e(TAG, "onRemoved for non-removal consumer: "
                             + Utils.getClientName(client));
@@ -289,7 +290,7 @@
         @Override
         public void onEnumerate(long deviceId, int fingerId, int groupId, int remaining) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof EnumerateConsumer)) {
                     Slog.e(TAG, "onEnumerate for non-enumerate consumer: "
                             + Utils.getClientName(client));
@@ -379,7 +380,7 @@
             mDaemon = null;
             mCurrentUserId = UserHandle.USER_NULL;
 
-            final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+            final BaseClientMonitor client = mScheduler.getCurrentClient();
             if (client instanceof Interruptable) {
                 Slog.e(TAG, "Sending ERROR_HW_UNAVAILABLE for client: " + client);
                 final Interruptable interruptable = (Interruptable) client;
@@ -486,7 +487,7 @@
                         hasEnrolled, mAuthenticatorIds);
         mScheduler.scheduleClientMonitor(client, new BaseClientMonitor.Callback() {
             @Override
-            public void onClientFinished(@NonNull BaseClientMonitor<?> clientMonitor,
+            public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
                     boolean success) {
                 if (success) {
                     mCurrentUserId = targetUserId;
@@ -560,7 +561,7 @@
                     shouldLogMetrics);
             mScheduler.scheduleClientMonitor(client, new BaseClientMonitor.Callback() {
                 @Override
-                public void onClientFinished(@NonNull BaseClientMonitor<?> clientMonitor,
+                public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
                         boolean success) {
                     if (success) {
                         // Update authenticatorIds
@@ -682,12 +683,12 @@
 
     @Override
     public long getAuthenticatorId(int sensorId, int userId) {
-        return mAuthenticatorIds.get(userId);
+        return mAuthenticatorIds.getOrDefault(userId, 0L);
     }
 
     @Override
     public void onPointerDown(int sensorId, int x, int y, float minor, float major) {
-        final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+        final BaseClientMonitor client = mScheduler.getCurrentClient();
         if (!(client instanceof Udfps)) {
             Slog.w(TAG, "onFingerDown received during client: " + client);
             return;
@@ -698,7 +699,7 @@
 
     @Override
     public void onPointerUp(int sensorId) {
-        final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+        final BaseClientMonitor client = mScheduler.getCurrentClient();
         if (!(client instanceof Udfps)) {
             Slog.w(TAG, "onFingerDown received during client: " + client);
             return;
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 3ea2366..2394a70 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
@@ -146,14 +146,14 @@
 
         class TestableInternalCallback extends InternalCallback {
             @Override
-            public void onClientStarted(BaseClientMonitor<?> clientMonitor) {
+            public void onClientStarted(BaseClientMonitor clientMonitor) {
                 super.onClientStarted(clientMonitor);
                 Slog.d(TAG, "Client started: " + clientMonitor);
                 mFingerprint21.setDebugMessage("Started: " + clientMonitor);
             }
 
             @Override
-            public void onClientFinished(BaseClientMonitor<?> clientMonitor, boolean success) {
+            public void onClientFinished(BaseClientMonitor clientMonitor, boolean success) {
                 super.onClientFinished(clientMonitor, success);
                 Slog.d(TAG, "Client finished: " + clientMonitor);
                 mFingerprint21.setDebugMessage("Finished: " + clientMonitor);
@@ -233,7 +233,7 @@
         public void onAuthenticated(long deviceId, int fingerId, int groupId,
                 ArrayList<Byte> token) {
             mHandler.post(() -> {
-                final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+                final BaseClientMonitor client = mScheduler.getCurrentClient();
                 if (!(client instanceof AuthenticationConsumer)) {
                     Slog.e(TAG, "Non authentication consumer: " + client);
                     return;
@@ -360,7 +360,7 @@
 
         @Override
         public void run() {
-            final BaseClientMonitor<?> client = mScheduler.getCurrentClient();
+            final BaseClientMonitor client = mScheduler.getCurrentClient();
 
             // We don't care about FingerprintDetectClient, since accept/rejects are both OK. UDFPS
             // rejects will just simulate the path where non-enrolled fingers are presented.
@@ -466,7 +466,7 @@
             Slog.d(TAG, "onFingerDown");
             final AuthenticationConsumer lastAuthenticatedConsumer =
                     mMockHalResultController.getLastAuthenticatedClient();
-            final BaseClientMonitor<?> currentScheduledClient = mScheduler.getCurrentClient();
+            final BaseClientMonitor currentScheduledClient = mScheduler.getCurrentClient();
 
             if (currentScheduledClient == null) {
                 Slog.d(TAG, "Not authenticating");
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 784e37b..13e2e4f 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
@@ -101,6 +101,13 @@
         }
     }
 
+    @Override
+    public void onError(int errorCode, int vendorCode) {
+        super.onError(errorCode, vendorCode);
+
+        UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
+    }
+
     private void resetFailedAttempts(int userId) {
         mLockoutFrameworkImpl.resetFailedAttemptsForUser(true /* clearAttemptCounter */, userId);
     }
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
index b2e3c33..8493af1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
@@ -113,6 +113,13 @@
     }
 
     @Override
+    public void onError(int errorCode, int vendorCode) {
+        super.onError(errorCode, vendorCode);
+
+        UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
+    }
+
+    @Override
     public void onPointerDown(int x, int y, float minor, float major) {
         UdfpsHelper.onFingerDown(getFreshDaemon(), x, y, minor, major);
     }
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java
index 2a4c2ef..f6ec4d9 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java
@@ -26,7 +26,7 @@
 import android.os.SELinux;
 import android.util.Slog;
 
-import com.android.server.biometrics.sensors.BaseClientMonitor;
+import com.android.server.biometrics.sensors.HalClientMonitor;
 
 import java.io.File;
 import java.util.Map;
@@ -34,7 +34,7 @@
 /**
  * Sets the HAL's current active user, and updates the framework's authenticatorId cache.
  */
-public class FingerprintUpdateActiveUserClient extends BaseClientMonitor<IBiometricsFingerprint> {
+public class FingerprintUpdateActiveUserClient extends HalClientMonitor<IBiometricsFingerprint> {
 
     private static final String TAG = "FingerprintUpdateActiveUserClient";
     private static final String FP_DATA_DIR = "fpdata";
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
index 1024556..26244e6 100644
--- a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
@@ -368,6 +368,7 @@
 
         @Override
         public void logDefaultNetworkValidity(boolean valid) {
+            NetworkStack.checkNetworkStackPermission(getContext());
             mDefaultNetworkMetrics.logDefaultNetworkValidity(SystemClock.elapsedRealtime(), valid);
         }
 
@@ -375,6 +376,7 @@
         public void logDefaultNetworkEvent(Network defaultNetwork, int score, boolean validated,
                 LinkProperties lp, NetworkCapabilities nc, Network previousDefaultNetwork,
                 int previousScore, LinkProperties previousLp, NetworkCapabilities previousNc) {
+            NetworkStack.checkNetworkStackPermission(getContext());
             final long timeMs = SystemClock.elapsedRealtime();
             mDefaultNetworkMetrics.logDefaultNetworkEvent(timeMs, defaultNetwork, score, validated,
                     lp, nc,  previousDefaultNetwork, previousScore, previousLp, previousNc);
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index c1b1b6a..952193b 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -246,11 +246,6 @@
             return;
         }
 
-        if (mNetwork.linkProperties == null) {
-            Log.e(TAG, "startClat: Can't start clat with null LinkProperties");
-            return;
-        }
-
         String baseIface = mNetwork.linkProperties.getInterfaceName();
         if (baseIface == null) {
             Log.e(TAG, "startClat: Can't start clat on null interface");
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index b0a73f1..ba6cbcd 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -136,12 +136,12 @@
     // This Network object should always be used if possible, so as to encourage reuse of the
     // enclosed socket factory and connection pool.  Avoid creating other Network objects.
     // This Network object is always valid.
-    public final Network network;
-    public LinkProperties linkProperties;
+    @NonNull public final Network network;
+    @NonNull public LinkProperties linkProperties;
     // This should only be modified by ConnectivityService, via setNetworkCapabilities().
     // TODO: make this private with a getter.
-    public NetworkCapabilities networkCapabilities;
-    public final NetworkAgentConfig networkAgentConfig;
+    @NonNull public NetworkCapabilities networkCapabilities;
+    @NonNull public final NetworkAgentConfig networkAgentConfig;
 
     // Underlying networks declared by the agent. Only set if supportsUnderlyingNetworks is true.
     // The networks in this list might be declared by a VPN app using setUnderlyingNetworks and are
@@ -329,6 +329,12 @@
             Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd,
             IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber,
             int creatorUid) {
+        Objects.requireNonNull(net);
+        Objects.requireNonNull(info);
+        Objects.requireNonNull(lp);
+        Objects.requireNonNull(nc);
+        Objects.requireNonNull(context);
+        Objects.requireNonNull(config);
         networkAgent = na;
         network = net;
         networkInfo = info;
@@ -536,19 +542,22 @@
         }
 
         @Override
-        public void sendNetworkCapabilities(NetworkCapabilities nc) {
+        public void sendNetworkCapabilities(@NonNull NetworkCapabilities nc) {
+            Objects.requireNonNull(nc);
             mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED,
                     new Pair<>(NetworkAgentInfo.this, nc)).sendToTarget();
         }
 
         @Override
-        public void sendLinkProperties(LinkProperties lp) {
+        public void sendLinkProperties(@NonNull LinkProperties lp) {
+            Objects.requireNonNull(lp);
             mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED,
                     new Pair<>(NetworkAgentInfo.this, lp)).sendToTarget();
         }
 
         @Override
-        public void sendNetworkInfo(NetworkInfo info) {
+        public void sendNetworkInfo(@NonNull NetworkInfo info) {
+            Objects.requireNonNull(info);
             mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_INFO_CHANGED,
                     new Pair<>(NetworkAgentInfo.this, info)).sendToTarget();
         }
@@ -603,7 +612,7 @@
      *
      * @return the old capabilities of this network.
      */
-    public synchronized NetworkCapabilities getAndSetNetworkCapabilities(
+    @NonNull public synchronized NetworkCapabilities getAndSetNetworkCapabilities(
             @NonNull final NetworkCapabilities nc) {
         final NetworkCapabilities oldNc = networkCapabilities;
         networkCapabilities = nc;
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index a65f809..fb1e819 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -439,6 +439,11 @@
         mEnableTeardown = enableTeardown;
     }
 
+    @VisibleForTesting
+    public boolean getEnableTeardown() {
+        return mEnableTeardown;
+    }
+
     /**
      * Update current state, dispatching event to listeners.
      */
@@ -2146,6 +2151,11 @@
 
         // Start a new LegacyVpnRunner and we are done!
         mVpnRunner = new LegacyVpnRunner(config, racoon, mtpd, profile);
+        startLegacyVpnRunner();
+    }
+
+    @VisibleForTesting
+    protected void startLegacyVpnRunner() {
         mVpnRunner.start();
     }
 
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 60e4595..55103ca 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -49,6 +49,7 @@
 import android.graphics.ColorSpace;
 import android.graphics.Point;
 import android.hardware.SensorManager;
+import android.hardware.devicestate.DeviceStateManager;
 import android.hardware.display.AmbientBrightnessDayStats;
 import android.hardware.display.BrightnessChangeEvent;
 import android.hardware.display.BrightnessConfiguration;
@@ -71,6 +72,7 @@
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.os.IBinder;
 import android.os.IBinder.DeathRecipient;
 import android.os.Looper;
@@ -100,7 +102,6 @@
 import android.view.Display;
 import android.view.DisplayEventReceiver;
 import android.view.DisplayInfo;
-import android.view.IDisplayFoldListener;
 import android.view.Surface;
 import android.view.SurfaceControl;
 
@@ -114,7 +115,6 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.UiThread;
-import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.wm.SurfaceAnimationThread;
 import com.android.server.wm.WindowManagerInternal;
 
@@ -360,8 +360,8 @@
     // Receives notifications about changes to Settings.
     private SettingsObserver mSettingsObserver;
 
-    // Received notifications of the display-fold action
-    private DisplayFoldListener mDisplayFoldListener;
+    // Received notifications of the device-state action (such as "fold", "unfold")
+    private DeviceStateManager mDeviceStateManager;
 
     private final boolean mAllowNonNativeRefreshRateOverride;
 
@@ -504,10 +504,11 @@
         synchronized (mSyncRoot) {
             mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
             mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
-            WindowManagerPolicy policy = LocalServices.getService(WindowManagerPolicy.class);
 
-            mDisplayFoldListener = new DisplayFoldListener();
-            policy.registerDisplayFoldListener(mDisplayFoldListener);
+            DeviceStateManager deviceStateManager =
+                    mContext.getSystemService(DeviceStateManager.class);
+            deviceStateManager.registerDeviceStateListener(new DeviceStateListener(),
+                    new HandlerExecutor(mHandler));
 
             scheduleTraversalLocked(false);
         }
@@ -2880,15 +2881,14 @@
         }
     }
 
-    class DisplayFoldListener extends IDisplayFoldListener.Stub {
+    /**
+     * Listens to changes in device state and reports the state to LogicalDisplayMapper.
+     */
+    class DeviceStateListener implements DeviceStateManager.DeviceStateListener {
         @Override
-        public void onDisplayFoldChanged(int displayId, boolean folded) {
-            // TODO: multi-display - IDisplayFoldListener callback only really works for the
-            // Display.DEFAULT_DISPLAY.
-            if (displayId == Display.DEFAULT_DISPLAY) {
-                synchronized (mSyncRoot) {
-                    mLogicalDisplayMapper.setDeviceFoldedLocked(folded);
-                }
+        public void onDeviceStateChanged(int deviceState) {
+            synchronized (mSyncRoot) {
+                mLogicalDisplayMapper.setDeviceStateLocked(deviceState);
             }
         }
     };
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index a127858..bb2fbed 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -103,6 +103,7 @@
 
     private final DisplayDeviceRepository mDisplayDeviceRepo;
     private final Listener mListener;
+    private final int mFoldedDeviceState;
 
     LogicalDisplayMapper(Context context, DisplayDeviceRepository repo, Listener listener) {
         mDisplayDeviceRepo = repo;
@@ -110,6 +111,9 @@
         mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);
         mDisplayDeviceRepo.addListener(this);
 
+        mFoldedDeviceState = context.getResources().getInteger(
+                com.android.internal.R.integer.config_foldedDeviceState);
+
         loadFoldedDisplayConfig(context);
     }
 
@@ -211,6 +215,10 @@
         }
     }
 
+    void setDeviceStateLocked(int state) {
+        setDeviceFoldedLocked(state == mFoldedDeviceState);
+    }
+
     void setDeviceFoldedLocked(boolean isFolded) {
         mIsFolded = isFolded;
         if (mIsFoldedOverride != null) {
diff --git a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
index 521ce69..a0d9e8e 100644
--- a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
+++ b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
@@ -20,15 +20,26 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.graphics.Typeface;
+import android.graphics.fonts.FontFamily;
+import android.graphics.fonts.FontFileUtil;
+import android.graphics.fonts.SystemFonts;
 import android.os.SharedMemory;
 import android.system.ErrnoException;
+import android.text.FontConfig;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
 import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.NioUtils;
+import java.nio.channels.FileChannel;
+import java.util.Map;
 
 /** A service for managing system fonts. */
 // TODO(b/173619554): Add API to update fonts.
@@ -36,6 +47,10 @@
 
     private static final String TAG = "FontManagerService";
 
+    // TODO: make this a DeviceConfig flag.
+    private static final boolean ENABLE_FONT_UPDATES = false;
+    private static final String FONT_FILES_DIR = "/data/fonts/files";
+
     /** Class to manage FontManagerService's lifecycle. */
     public static final class Lifecycle extends SystemService {
         private final FontManagerService mService;
@@ -52,37 +67,132 @@
                         @Override
                         @Nullable
                         public SharedMemory getSerializedSystemFontMap() {
-                            return mService.getSerializedSystemFontMap();
+                            if (!Typeface.ENABLE_LAZY_TYPEFACE_INITIALIZATION) {
+                                return null;
+                            }
+                            return mService.getCurrentFontSettings().getSerializedSystemFontMap();
                         }
                     });
         }
     }
 
-    @GuardedBy("this")
-    @Nullable
-    private SharedMemory mSerializedSystemFontMap = null;
+    private static class OtfFontFileParser implements UpdatableFontDir.FontFileParser {
+        @Override
+        public long getVersion(File file) throws IOException {
+            ByteBuffer buffer = mmap(file);
+            try {
+                return FontFileUtil.getRevision(buffer, 0);
+            } finally {
+                NioUtils.freeDirectBuffer(buffer);
+            }
+        }
+
+        private static ByteBuffer mmap(File file) throws IOException {
+            try (FileInputStream in = new FileInputStream(file)) {
+                FileChannel fileChannel = in.getChannel();
+                return fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size());
+            }
+        }
+    }
 
     @Nullable
-    private SharedMemory getSerializedSystemFontMap() {
-        if (!Typeface.ENABLE_LAZY_TYPEFACE_INITIALIZATION) {
-            return null;
-        }
+    private final UpdatableFontDir mUpdatableFontDir;
+
+    @GuardedBy("FontManagerService.this")
+    @Nullable SystemFontSettings mCurrentFontSettings = null;
+
+    private FontManagerService() {
+        mUpdatableFontDir = ENABLE_FONT_UPDATES
+                ? new UpdatableFontDir(new File(FONT_FILES_DIR), new OtfFontFileParser()) : null;
+    }
+
+    @NonNull private SystemFontSettings getCurrentFontSettings() {
         synchronized (FontManagerService.this) {
-            if (mSerializedSystemFontMap == null) {
-                mSerializedSystemFontMap = createSerializedSystemFontMapLocked();
+            if (mCurrentFontSettings == null) {
+                mCurrentFontSettings = SystemFontSettings.create(mUpdatableFontDir);
             }
+            return mCurrentFontSettings;
+        }
+    }
+
+    private boolean installFontFile(String name, FileDescriptor fd) {
+        if (mUpdatableFontDir == null) return false;
+        synchronized (FontManagerService.this) {
+            try {
+                mUpdatableFontDir.installFontFile(name, fd);
+            } catch (IOException e) {
+                Slog.w(TAG, "Failed to install font file: " + name, e);
+                return false;
+            }
+            // Create updated font map in the next getSerializedSystemFontMap() call.
+            mCurrentFontSettings = null;
+            return true;
+        }
+    }
+
+    private static class SystemFontSettings {
+        private final @NonNull SharedMemory mSerializedSystemFontMap;
+        private final @NonNull FontConfig mSystemFontConfig;
+        private final @NonNull Map<String, FontFamily[]> mSystemFallbackMap;
+        private final @NonNull Map<String, Typeface> mSystemTypefaceMap;
+
+        SystemFontSettings(
+                @NonNull SharedMemory serializedSystemFontMap,
+                @NonNull FontConfig systemFontConfig,
+                @NonNull Map<String, FontFamily[]> systemFallbackMap,
+                @NonNull Map<String, Typeface> systemTypefaceMap) {
+            mSerializedSystemFontMap = serializedSystemFontMap;
+            mSystemFontConfig = systemFontConfig;
+            mSystemFallbackMap = systemFallbackMap;
+            mSystemTypefaceMap = systemTypefaceMap;
+        }
+
+        public @NonNull SharedMemory getSerializedSystemFontMap() {
             return mSerializedSystemFontMap;
         }
-    }
 
-    @Nullable
-    private SharedMemory createSerializedSystemFontMapLocked() {
-        // TODO(b/173619554): use updated fonts.
-        try {
-            return Typeface.serializeFontMap(Typeface.getSystemFontMap());
-        } catch (IOException | ErrnoException e) {
-            Slog.e(TAG, "Failed to serialize SystemServer system font map", e);
+        public @NonNull FontConfig getSystemFontConfig() {
+            return mSystemFontConfig;
         }
-        return null;
-    }
+
+        public @NonNull Map<String, FontFamily[]> getSystemFallbackMap() {
+            return mSystemFallbackMap;
+        }
+
+        public @NonNull Map<String, Typeface> getSystemTypefaceMap() {
+            return mSystemTypefaceMap;
+        }
+
+        public static @Nullable SystemFontSettings create(
+                @Nullable UpdatableFontDir updatableFontDir) {
+            if (updatableFontDir != null) {
+                final FontConfig fontConfig = SystemFonts.getSystemFontConfig(
+                        updatableFontDir.getFontFileMap());
+                final Map<String, FontFamily[]> fallback =
+                        SystemFonts.buildSystemFallback(fontConfig);
+                final Map<String, Typeface> typefaceMap =
+                        SystemFonts.buildSystemTypefaces(fontConfig, fallback);
+
+                try {
+                    final SharedMemory shm = Typeface.serializeFontMap(typefaceMap);
+                    return new SystemFontSettings(shm, fontConfig, fallback, typefaceMap);
+                } catch (IOException | ErrnoException e) {
+                    Slog.w(TAG, "Failed to serialize updatable font map. "
+                            + "Retrying with system image fonts.", e);
+                }
+            }
+
+            final FontConfig fontConfig = SystemFonts.getSystemPreinstalledFontConfig();
+            final Map<String, FontFamily[]> fallback = SystemFonts.buildSystemFallback(fontConfig);
+            final Map<String, Typeface> typefaceMap =
+                    SystemFonts.buildSystemTypefaces(fontConfig, fallback);
+            try {
+                final SharedMemory shm = Typeface.serializeFontMap(typefaceMap);
+                return new SystemFontSettings(shm, fontConfig, fallback, typefaceMap);
+            } catch (IOException | ErrnoException e) {
+                Slog.e(TAG, "Failed to serialize SystemServer system font map", e);
+            }
+            return null;
+        }
+    };
 }
diff --git a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
new file mode 100644
index 0000000..7306471
--- /dev/null
+++ b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.graphics.fonts;
+
+import android.os.FileUtils;
+import android.util.Base64;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.security.SecureRandom;
+import java.util.HashMap;
+import java.util.Map;
+
+final class UpdatableFontDir {
+
+    private static final String TAG = "UpdatableFontDir";
+    private static final String RANDOM_DIR_PREFIX = "~~";
+
+    /** Interface to mock font file access in tests. */
+    interface FontFileParser {
+        long getVersion(File file) throws IOException;
+    }
+
+    /** Data class to hold font file path and version. */
+    static final class FontFileInfo {
+        final File mFile;
+        final long mVersion;
+
+        FontFileInfo(File file, long version) {
+            mFile = file;
+            mVersion = version;
+        }
+    }
+
+    /**
+     * Root directory for storing updated font files. Each font file is stored in a unique random
+     * dir. The font file path would be {@code mFilesDir/~~{randomStr}/{fontFileName}}.
+     */
+    private final File mFilesDir;
+    private final FontFileParser mParser;
+    @GuardedBy("UpdatableFontDir.this")
+    private final Map<String, FontFileInfo> mFontFileInfoMap = new HashMap<>();
+
+    UpdatableFontDir(File filesDir, FontFileParser parser) {
+        mFilesDir = filesDir;
+        mParser = parser;
+        loadFontFileMap();
+    }
+
+    private void loadFontFileMap() {
+        synchronized (UpdatableFontDir.this) {
+            mFontFileInfoMap.clear();
+            File[] dirs = mFilesDir.listFiles();
+            if (dirs == null) return;
+            for (File dir : dirs) {
+                if (!dir.getName().startsWith(RANDOM_DIR_PREFIX)) continue;
+                File[] files = dir.listFiles();
+                if (files == null || files.length != 1) continue;
+                addFileToMapLocked(files[0], true);
+            }
+        }
+    }
+
+    void installFontFile(String name, FileDescriptor fd) throws IOException {
+        // TODO: Validate name.
+        synchronized (UpdatableFontDir.this) {
+            // TODO: proper error handling
+            File newDir = getRandomDir(mFilesDir);
+            if (!newDir.mkdir()) {
+                throw new IOException("Failed to create a new dir");
+            }
+            File newFontFile = new File(newDir, name);
+            try (FileOutputStream out = new FileOutputStream(newFontFile)) {
+                FileUtils.copy(fd, out.getFD());
+            }
+            addFileToMapLocked(newFontFile, false);
+        }
+    }
+
+    /**
+     * Given {@code parent}, returns {@code parent/~~[randomStr]}.
+     * Makes sure that {@code parent/~~[randomStr]} directory doesn't exist.
+     * Notice that this method doesn't actually create any directory.
+     */
+    private static File getRandomDir(File parent) {
+        SecureRandom random = new SecureRandom();
+        byte[] bytes = new byte[16];
+        File dir;
+        do {
+            random.nextBytes(bytes);
+            String dirName = RANDOM_DIR_PREFIX
+                    + Base64.encodeToString(bytes, Base64.URL_SAFE | Base64.NO_WRAP);
+            dir = new File(parent, dirName);
+        } while (dir.exists());
+        return dir;
+    }
+
+    private void addFileToMapLocked(File file, boolean deleteOldFile) {
+        final long version;
+        try {
+            version = mParser.getVersion(file);
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to read font file", e);
+            return;
+        }
+        if (version == -1) {
+            Slog.e(TAG, "Invalid font file");
+            return;
+        }
+        FontFileInfo info = mFontFileInfoMap.get(file.getName());
+        if (info == null) {
+            // TODO: check version of font in /system/fonts and /product/fonts
+            mFontFileInfoMap.put(file.getName(), new FontFileInfo(file, version));
+        } else if (info.mVersion < version) {
+            if (deleteOldFile) {
+                FileUtils.deleteContentsAndDir(info.mFile.getParentFile());
+            }
+            mFontFileInfoMap.put(file.getName(), new FontFileInfo(file, version));
+        }
+    }
+
+    Map<String, File> getFontFileMap() {
+        Map<String, File> map = new HashMap<>();
+        synchronized (UpdatableFontDir.this) {
+            for (Map.Entry<String, FontFileInfo> entry : mFontFileInfoMap.entrySet()) {
+                map.put(entry.getKey(), entry.getValue().mFile);
+            }
+        }
+        return map;
+    }
+}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index a207a96..23c70ee 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -1856,6 +1856,13 @@
         }
 
         VibrationInfo(VibrationEffect effect) {
+            // First replace prebaked effects with its fallback, if any available.
+            if (effect instanceof VibrationEffect.Prebaked) {
+                VibrationEffect fallback = ((VibrationEffect.Prebaked) effect).getFallbackEffect();
+                if (fallback != null) {
+                    effect = fallback;
+                }
+            }
             if (effect instanceof VibrationEffect.OneShot) {
                 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) effect;
                 mPattern = new long[] { 0, oneShot.getDuration() };
@@ -1882,8 +1889,7 @@
                     throw new ArrayIndexOutOfBoundsException();
                 }
             } else {
-                // TODO: Add support for prebaked effects
-                Slog.w(TAG, "Pre-baked effects aren't supported on input devices");
+                Slog.w(TAG, "Pre-baked and composed effects aren't supported on input devices");
             }
         }
     }
@@ -2059,8 +2065,7 @@
 
     @Override // Binder call
     public InputSensorInfo[] getSensorList(int deviceId) {
-        InputSensorInfo[] sensors = nativeGetSensorList(mPtr, deviceId);
-        return sensors;
+        return nativeGetSensorList(mPtr, deviceId);
     }
 
     @Override // Binder call
diff --git a/services/core/java/com/android/server/media/metrics/PlaybackMetricsManagerService.java b/services/core/java/com/android/server/media/metrics/PlaybackMetricsManagerService.java
index b576810..5fa7998 100644
--- a/services/core/java/com/android/server/media/metrics/PlaybackMetricsManagerService.java
+++ b/services/core/java/com/android/server/media/metrics/PlaybackMetricsManagerService.java
@@ -21,6 +21,9 @@
 import android.media.metrics.NetworkEvent;
 import android.media.metrics.PlaybackErrorEvent;
 import android.media.metrics.PlaybackMetrics;
+import android.media.metrics.PlaybackStateEvent;
+import android.media.metrics.TrackChangeEvent;
+import android.os.Binder;
 import android.util.Base64;
 import android.util.StatsEvent;
 import android.util.StatsLog;
@@ -54,6 +57,33 @@
     private final class BinderService extends IPlaybackMetricsManager.Stub {
         @Override
         public void reportPlaybackMetrics(String sessionId, PlaybackMetrics metrics, int userId) {
+            StatsEvent statsEvent = StatsEvent.newBuilder()
+                    .setAtomId(320)
+                    .writeInt(Binder.getCallingUid())
+                    .writeString(sessionId)
+                    .writeLong(metrics.getMediaDurationMillis())
+                    .writeInt(metrics.getStreamSource())
+                    .writeInt(metrics.getStreamType())
+                    .writeInt(metrics.getPlaybackType())
+                    .writeInt(metrics.getDrmType())
+                    .writeInt(metrics.getContentType())
+                    .writeString(metrics.getPlayerName())
+                    .writeString(metrics.getPlayerVersion())
+                    .writeByteArray(new byte[0]) // TODO: write experiments proto
+                    .writeInt(metrics.getVideoFramesPlayed())
+                    .writeInt(metrics.getVideoFramesDropped())
+                    .writeInt(metrics.getAudioUnderrunCount())
+                    .writeLong(metrics.getNetworkBytesRead())
+                    .writeLong(metrics.getLocalBytesRead())
+                    .writeLong(metrics.getNetworkTransferDurationMillis())
+                    .usePooledBuffer()
+                    .build();
+            StatsLog.write(statsEvent);
+        }
+
+        @Override
+        public void reportPlaybackStateEvent(
+                String sessionId, PlaybackStateEvent event, int userId) {
             // TODO: log it to statsd
         }
 
@@ -91,5 +121,30 @@
                     .build();
             StatsLog.write(statsEvent);
         }
+
+        @Override
+        public void reportTrackChangeEvent(
+                String sessionId, TrackChangeEvent event, int userId) {
+            StatsEvent statsEvent = StatsEvent.newBuilder()
+                    .setAtomId(321)
+                    .writeString(sessionId)
+                    .writeInt(event.getTrackState())
+                    .writeInt(event.getTrackChangeReason())
+                    .writeString(event.getContainerMimeType())
+                    .writeString(event.getSampleMimeType())
+                    .writeString(event.getCodecName())
+                    .writeInt(event.getBitrate())
+                    .writeLong(event.getTimeSincePlaybackCreatedMillis())
+                    .writeInt(event.getTrackType())
+                    .writeString(event.getLanguage())
+                    .writeString(event.getLanguageRegion())
+                    .writeInt(event.getChannelCount())
+                    .writeInt(event.getSampleRate())
+                    .writeInt(event.getWidth())
+                    .writeInt(event.getHeight())
+                    .usePooledBuffer()
+                    .build();
+            StatsLog.write(statsEvent);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index ea1d8da..ea2788c 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -34,7 +34,6 @@
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkInfo.State;
 import android.os.Handler;
-import android.security.Credentials;
 import android.security.KeyStore;
 import android.text.TextUtils;
 import android.util.Log;
@@ -70,6 +69,7 @@
     @NonNull private final Handler mHandler;
     @NonNull private final Vpn mVpn;
     @NonNull private final VpnProfile mProfile;
+    @NonNull private final KeyStore mKeyStore;
 
     @NonNull private final Object mStateLock = new Object();
 
@@ -81,13 +81,10 @@
 
     private int mErrorCount;
 
-    public static boolean isEnabled() {
-        return KeyStore.getInstance().contains(Credentials.LOCKDOWN_VPN);
-    }
-
     public LockdownVpnTracker(@NonNull Context context,
             @NonNull ConnectivityService connService,
             @NonNull Handler handler,
+            @NonNull KeyStore keyStore,
             @NonNull Vpn vpn,
             @NonNull VpnProfile profile) {
         mContext = Objects.requireNonNull(context);
@@ -95,6 +92,7 @@
         mHandler = Objects.requireNonNull(handler);
         mVpn = Objects.requireNonNull(vpn);
         mProfile = Objects.requireNonNull(profile);
+        mKeyStore = Objects.requireNonNull(keyStore);
         mNotificationManager = mContext.getSystemService(NotificationManager.class);
 
         final Intent configIntent = new Intent(ACTION_VPN_SETTINGS);
@@ -157,7 +155,7 @@
                 try {
                     // Use the privileged method because Lockdown VPN is initiated by the system, so
                     // no additional permission checks are necessary.
-                    mVpn.startLegacyVpnPrivileged(mProfile, KeyStore.getInstance(), egressProp);
+                    mVpn.startLegacyVpnPrivileged(mProfile, mKeyStore, egressProp);
                 } catch (IllegalStateException e) {
                     mAcceptedEgressIface = null;
                     Log.e(TAG, "Failed to start VPN", e);
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index cbd973a..61c8b17 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -50,6 +50,7 @@
 import android.service.notification.NotificationListenerService;
 import android.service.notification.RankingHelperProto;
 import android.text.TextUtils;
+import android.text.format.DateUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.IntArray;
@@ -101,6 +102,7 @@
     private static final int NOTIFICATION_PREFERENCES_PULL_LIMIT = 1000;
     private static final int NOTIFICATION_CHANNEL_PULL_LIMIT = 2000;
     private static final int NOTIFICATION_CHANNEL_GROUP_PULL_LIMIT = 1000;
+    private static final int NOTIFICATION_CHANNEL_DELETION_RETENTION_DAYS = 30;
 
     @VisibleForTesting
     static final String TAG_RANKING = "ranking";
@@ -324,12 +326,8 @@
                                                 channel.setImportanceLockedByOEM(true);
                                             }
                                         }
-                                        boolean isInvalidShortcutChannel =
-                                                channel.getConversationId() != null &&
-                                                        channel.getConversationId().contains(
-                                                                PLACEHOLDER_CONVERSATION_ID);
-                                        if (mAllowInvalidShortcuts || (!mAllowInvalidShortcuts
-                                                && !isInvalidShortcutChannel)) {
+
+                                        if (isShortcutOk(channel) && isDeletionOk(channel)) {
                                             r.channels.put(id, channel);
                                         }
                                     }
@@ -369,6 +367,26 @@
         throw new IllegalStateException("Failed to reach END_DOCUMENT");
     }
 
+    private boolean isShortcutOk(NotificationChannel channel) {
+        boolean isInvalidShortcutChannel =
+                channel.getConversationId() != null &&
+                        channel.getConversationId().contains(
+                                PLACEHOLDER_CONVERSATION_ID);
+        return mAllowInvalidShortcuts || (!mAllowInvalidShortcuts && !isInvalidShortcutChannel);
+    }
+
+    private boolean isDeletionOk(NotificationChannel nc) {
+        if (!nc.isDeleted()) {
+            return true;
+        }
+        long boundary = System.currentTimeMillis() - (
+                DateUtils.DAY_IN_MILLIS * NOTIFICATION_CHANNEL_DELETION_RETENTION_DAYS);
+        if (nc.getDeletedTimeMs() <= boundary) {
+            return false;
+        }
+        return true;
+    }
+
     private PackagePreferences getPackagePreferencesLocked(String pkg, int uid) {
         final String key = packagePreferencesKey(pkg, uid);
         return mPackagePreferences.get(key);
@@ -828,6 +846,7 @@
                 if (existing.isDeleted()) {
                     // The existing channel was deleted - undelete it.
                     existing.setDeleted(false);
+                    existing.setDeletedTimeMs(-1);
                     needsPolicyFileChange = true;
                     wasUndeleted = true;
 
@@ -1119,6 +1138,7 @@
     private void deleteNotificationChannelLocked(NotificationChannel channel, String pkg, int uid) {
         if (!channel.isDeleted()) {
             channel.setDeleted(true);
+            channel.setDeletedTimeMs(System.currentTimeMillis());
             LogMaker lm = getChannelLog(channel, pkg);
             lm.setType(com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_CLOSE);
             MetricsLogger.action(lm);
@@ -1479,6 +1499,7 @@
                 if (nc.getConversationId() != null
                         && conversationIds.contains(nc.getConversationId())) {
                     nc.setDeleted(true);
+                    nc.setDeletedTimeMs(System.currentTimeMillis());
                     LogMaker lm = getChannelLog(nc, pkg);
                     lm.setType(
                             com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_CLOSE);
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index 01eeb31..ef0f0ee 100644
--- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -21,6 +21,7 @@
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.os.Binder;
 import android.os.BugreportParams;
@@ -31,6 +32,7 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserManager;
+import android.telephony.TelephonyManager;
 import android.util.ArraySet;
 import android.util.Slog;
 
@@ -53,11 +55,13 @@
     private final Object mLock = new Object();
     private final Context mContext;
     private final AppOpsManager mAppOps;
+    private final TelephonyManager mTelephonyManager;
     private final ArraySet<String> mBugreportWhitelistedPackages;
 
     BugreportManagerServiceImpl(Context context) {
         mContext = context;
-        mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+        mAppOps = context.getSystemService(AppOpsManager.class);
+        mTelephonyManager = context.getSystemService(TelephonyManager.class);
         mBugreportWhitelistedPackages =
                 SystemConfig.getInstance().getBugreportWhitelistedPackages();
     }
@@ -67,11 +71,14 @@
     public void startBugreport(int callingUidUnused, String callingPackage,
             FileDescriptor bugreportFd, FileDescriptor screenshotFd,
             int bugreportMode, IDumpstateListener listener, boolean isScreenshotRequested) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, "startBugreport");
         Objects.requireNonNull(callingPackage);
         Objects.requireNonNull(bugreportFd);
         Objects.requireNonNull(listener);
         validateBugreportMode(bugreportMode);
+
+        int callingUid = Binder.getCallingUid();
+        enforcePermission(callingPackage, callingUid, bugreportMode
+                == BugreportParams.BUGREPORT_MODE_TELEPHONY /* checkCarrierPrivileges */);
         final long identity = Binder.clearCallingIdentity();
         try {
             ensureIsPrimaryUser();
@@ -79,13 +86,6 @@
             Binder.restoreCallingIdentity(identity);
         }
 
-        int callingUid = Binder.getCallingUid();
-        mAppOps.checkPackage(callingUid, callingPackage);
-
-        if (!mBugreportWhitelistedPackages.contains(callingPackage)) {
-            throw new SecurityException(
-                    callingPackage + " is not whitelisted to use Bugreport API");
-        }
         synchronized (mLock) {
             startBugreportLocked(callingUid, callingPackage, bugreportFd, screenshotFd,
                     bugreportMode, listener, isScreenshotRequested);
@@ -93,12 +93,10 @@
     }
 
     @Override
-    @RequiresPermission(android.Manifest.permission.DUMP)
+    @RequiresPermission(android.Manifest.permission.DUMP) // or carrier privileges
     public void cancelBugreport(int callingUidUnused, String callingPackage) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP,
-                "cancelBugreport");
         int callingUid = Binder.getCallingUid();
-        mAppOps.checkPackage(callingUid, callingPackage);
+        enforcePermission(callingPackage, callingUid, true /* checkCarrierPrivileges */);
 
         synchronized (mLock) {
             IDumpstate ds = getDumpstateBinderServiceLocked();
@@ -134,6 +132,34 @@
         }
     }
 
+    private void enforcePermission(
+            String callingPackage, int callingUid, boolean checkCarrierPrivileges) {
+        mAppOps.checkPackage(callingUid, callingPackage);
+
+        // To gain access through the DUMP permission, the OEM has to allow this package explicitly
+        // via sysconfig and privileged permissions.
+        if (mBugreportWhitelistedPackages.contains(callingPackage)
+                && mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                        == PackageManager.PERMISSION_GRANTED) {
+            return;
+        }
+        // For carrier privileges, this can include user-installed apps. This is essentially a
+        // function of the current active SIM(s) in the device to let carrier apps through.
+        if (checkCarrierPrivileges
+                && mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(callingPackage)
+                        == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+            return;
+        }
+
+        String message =
+                callingPackage
+                        + " does not hold the DUMP permission or is not bugreport-whitelisted "
+                        + (checkCarrierPrivileges ? "and does not have carrier privileges " : "")
+                        + "to request a bugreport";
+        Slog.w(TAG, message);
+        throw new SecurityException(message);
+    }
+
     /**
      * Validates that the current user is the primary user.
      *
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index b65fc73..2b5c393 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -71,6 +71,7 @@
 import android.content.pm.IPackageInstallObserver2;
 import android.content.pm.IPackageInstallerSession;
 import android.content.pm.IPackageInstallerSessionFileSystemConnector;
+import android.content.pm.IPackageLoadingProgressCallback;
 import android.content.pm.InstallationFile;
 import android.content.pm.InstallationFileParcel;
 import android.content.pm.PackageInfo;
@@ -186,6 +187,7 @@
     static final String TAG_CHILD_SESSION = "childSession";
     static final String TAG_SESSION_FILE = "sessionFile";
     static final String TAG_SESSION_CHECKSUM = "sessionChecksum";
+    static final String TAG_SESSION_CHECKSUM_SIGNATURE = "sessionChecksumSignature";
     private static final String TAG_GRANTED_RUNTIME_PERMISSION = "granted-runtime-permission";
     private static final String TAG_WHITELISTED_RESTRICTED_PERMISSION =
             "whitelisted-restricted-permission";
@@ -319,6 +321,8 @@
     private float mProgress = 0;
     @GuardedBy("mLock")
     private float mReportedProgress = -1;
+    @GuardedBy("mLock")
+    private float mIncrementalProgress = 0;
 
     /** State of the session. */
     @GuardedBy("mLock")
@@ -397,8 +401,26 @@
     @GuardedBy("mLock")
     private ArraySet<FileEntry> mFiles = new ArraySet<>();
 
+    static class PerFileChecksum {
+        private final Checksum[] mChecksums;
+        private final byte[] mSignature;
+
+        PerFileChecksum(Checksum[] checksums, byte[] signature) {
+            mChecksums = checksums;
+            mSignature = signature;
+        }
+
+        Checksum[] getChecksums() {
+            return this.mChecksums;
+        }
+
+        byte[] getSignature() {
+            return this.mSignature;
+        }
+    }
+
     @GuardedBy("mLock")
-    private ArrayMap<String, Checksum[]> mChecksums = new ArrayMap<>();
+    private ArrayMap<String, PerFileChecksum> mChecksums = new ArrayMap<>();
 
     @Nullable
     final StagedSession mStagedSession;
@@ -921,7 +943,7 @@
             int sessionId, int userId, int installerUid, @NonNull InstallSource installSource,
             SessionParams params, long createdMillis, long committedMillis,
             File stageDir, String stageCid, InstallationFile[] files,
-            ArrayMap<String, List<Checksum>> checksums,
+            ArrayMap<String, PerFileChecksum> checksums,
             boolean prepared, boolean committed, boolean destroyed, boolean sealed,
             @Nullable int[] childSessionIds, int parentSessionId, boolean isReady,
             boolean isFailed, boolean isApplied, int stagedSessionErrorCode,
@@ -967,11 +989,7 @@
         }
 
         if (checksums != null) {
-            for (int i = 0, isize = checksums.size(); i < isize; ++i) {
-                final String fileName = checksums.keyAt(i);
-                final List<Checksum> fileChecksums = checksums.valueAt(i);
-                mChecksums.put(fileName, fileChecksums.toArray(new Checksum[fileChecksums.size()]));
-            }
+            mChecksums.putAll(checksums);
         }
 
         if (!params.isMultiPackage && (stageDir == null) == (stageCid == null)) {
@@ -1182,7 +1200,12 @@
 
     @GuardedBy("mLock")
     private void computeProgressLocked(boolean forcePublish) {
-        mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f)
+        // This method is triggered when the client progress is updated or the incremental progress
+        // is updated. For incremental installs, ignore the progress values reported from client.
+        // Instead, only use the progress reported by IncFs as the percentage of loading completion.
+        final float loadingProgress =
+                isIncrementalInstallation() ? mIncrementalProgress : mClientProgress;
+        mProgress = MathUtils.constrain(loadingProgress * 0.8f, 0f, 0.8f)
                 + MathUtils.constrain(mInternalProgress * 0.2f, 0f, 0.2f);
 
         // Only publish when meaningful change
@@ -1253,7 +1276,8 @@
     }
 
     @Override
-    public void addChecksums(String name, @NonNull Checksum[] checksums) {
+    public void setChecksums(String name, @NonNull Checksum[] checksums,
+            @Nullable byte[] signature) {
         if (checksums.length == 0) {
             return;
         }
@@ -1269,6 +1293,17 @@
             throw new IllegalStateException("Can't obtain calling installer's package.");
         }
 
+        if (signature != null && signature.length != 0) {
+            final boolean standardMode = PackageManagerServiceUtils.isApkVerityEnabled();
+            final boolean legacyMode = PackageManagerServiceUtils.isLegacyApkVerityEnabled();
+            if (!standardMode || legacyMode) {
+                Slog.e(TAG,
+                        "Can't enforce checksum's signature: Apk-Verity is disabled or in legacy "
+                                + "mode.");
+                signature = null;
+            }
+        }
+
         synchronized (mLock) {
             assertCallerIsOwnerOrRootLocked();
             assertPreparedAndNotCommittedOrDestroyedLocked("addChecksums");
@@ -1277,7 +1312,7 @@
                 throw new IllegalStateException("Duplicate checksums.");
             }
 
-            mChecksums.put(name, checksums);
+            mChecksums.put(name, new PerFileChecksum(checksums, signature));
         }
     }
 
@@ -3032,15 +3067,25 @@
         maybeStageFsveritySignatureLocked(dexMetadataFile, targetDexMetadataFile);
     }
 
+    private void storeBytesToInstallationFile(final String localPath, final String absolutePath,
+            final byte[] bytes) throws IOException {
+        if (!isIncrementalInstallation() || mIncrementalFileStorages == null) {
+            FileUtils.bytesToFile(absolutePath, bytes);
+        } else {
+            mIncrementalFileStorages.makeFile(localPath, bytes);
+        }
+    }
+
     @GuardedBy("mLock")
     private void maybeStageDigestsLocked(File origFile, File targetFile, String splitName)
             throws PackageManagerException {
-        final Checksum[] checksums = mChecksums.get(origFile.getName());
-        if (checksums == null) {
+        final PerFileChecksum perFileChecksum = mChecksums.get(origFile.getName());
+        if (perFileChecksum == null) {
             return;
         }
         mChecksums.remove(origFile.getName());
 
+        final Checksum[] checksums = perFileChecksum.getChecksums();
         if (checksums.length == 0) {
             return;
         }
@@ -3048,14 +3093,24 @@
         final String targetDigestsPath = ApkChecksums.buildDigestsPathForApk(targetFile.getName());
         final File targetDigestsFile = new File(stageDir, targetDigestsPath);
         try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+            // Storing and staging checksums.
             ApkChecksums.writeChecksums(os, checksums);
-            final byte[] checksumsBytes = os.toByteArray();
+            storeBytesToInstallationFile(targetDigestsPath, targetDigestsFile.getAbsolutePath(),
+                    os.toByteArray());
+            stageFileLocked(targetDigestsFile, targetDigestsFile);
 
-            if (!isIncrementalInstallation() || mIncrementalFileStorages == null) {
-                FileUtils.bytesToFile(targetDigestsFile.getAbsolutePath(), checksumsBytes);
-            } else {
-                mIncrementalFileStorages.makeFile(targetDigestsPath, checksumsBytes);
+            final byte[] signature = perFileChecksum.getSignature();
+            if (signature == null || signature.length == 0) {
+                return;
             }
+
+            // Storing and staging signature.
+            final String targetDigestsSignaturePath = VerityUtils.getFsveritySignatureFilePath(
+                    targetDigestsPath);
+            final File targetDigestsSignatureFile = new File(stageDir, targetDigestsSignaturePath);
+            storeBytesToInstallationFile(targetDigestsSignaturePath,
+                    targetDigestsSignatureFile.getAbsolutePath(), signature);
+            stageFileLocked(targetDigestsSignatureFile, targetDigestsSignatureFile);
         } catch (CertificateException e) {
             throw new PackageManagerException(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING,
                     "Failed to encode certificate for " + mPackageName, e);
@@ -3063,8 +3118,6 @@
             throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
                     "Failed to store digests for " + mPackageName, e);
         }
-
-        stageFileLocked(targetDigestsFile, targetDigestsFile);
     }
 
     @GuardedBy("mLock")
@@ -3704,7 +3757,16 @@
             try {
                 mIncrementalFileStorages = IncrementalFileStorages.initialize(mContext, stageDir,
                         params, statusListener, healthCheckParams, healthListener, addedFiles,
-                        perUidReadTimeouts);
+                        perUidReadTimeouts,
+                        new IPackageLoadingProgressCallback.Stub() {
+                            @Override
+                            public void onPackageLoadingProgressChanged(float progress) {
+                                synchronized (mLock) {
+                                    mIncrementalProgress = progress;
+                                    computeProgressLocked(true);
+                                }
+                            }
+                        });
                 return false;
             } catch (IOException e) {
                 throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE, e.getMessage(),
@@ -4277,7 +4339,8 @@
 
             for (int i = 0, isize = mChecksums.size(); i < isize; ++i) {
                 final String fileName = mChecksums.keyAt(i);
-                final Checksum[] checksums = mChecksums.valueAt(i);
+                final PerFileChecksum perFileChecksum = mChecksums.valueAt(i);
+                final Checksum[] checksums = perFileChecksum.getChecksums();
                 for (Checksum checksum : checksums) {
                     out.startTag(null, TAG_SESSION_CHECKSUM);
                     writeStringAttribute(out, ATTR_NAME, fileName);
@@ -4286,6 +4349,19 @@
                     out.endTag(null, TAG_SESSION_CHECKSUM);
                 }
             }
+            for (int i = 0, isize = mChecksums.size(); i < isize; ++i) {
+                final String fileName = mChecksums.keyAt(i);
+                final PerFileChecksum perFileChecksum = mChecksums.valueAt(i);
+                final byte[] signature = perFileChecksum.getSignature();
+                if (signature == null || signature.length == 0) {
+                    continue;
+                }
+                out.startTag(null, TAG_SESSION_CHECKSUM_SIGNATURE);
+                writeStringAttribute(out, ATTR_NAME, fileName);
+                writeByteArrayAttribute(out, ATTR_SIGNATURE, signature);
+                out.endTag(null, TAG_SESSION_CHECKSUM_SIGNATURE);
+            }
+
         }
 
         out.endTag(null, TAG_SESSION);
@@ -4401,6 +4477,7 @@
         List<Integer> childSessionIds = new ArrayList<>();
         List<InstallationFile> files = new ArrayList<>();
         ArrayMap<String, List<Checksum>> checksums = new ArrayMap<>();
+        ArrayMap<String, byte[]> signatures = new ArrayMap<>();
         int outerDepth = in.getDepth();
         int type;
         while ((type = in.next()) != XmlPullParser.END_DOCUMENT
@@ -4443,6 +4520,11 @@
                 }
                 fileChecksums.add(checksum);
             }
+            if (TAG_SESSION_CHECKSUM_SIGNATURE.equals(in.getName())) {
+                final String fileName = readStringAttribute(in, ATTR_NAME);
+                final byte[] signature = readByteArrayAttribute(in, ATTR_SIGNATURE);
+                signatures.put(fileName, signature);
+            }
         }
 
         if (grantedRuntimePermissions.size() > 0) {
@@ -4471,13 +4553,25 @@
             fileArray = files.toArray(EMPTY_INSTALLATION_FILE_ARRAY);
         }
 
+        ArrayMap<String, PerFileChecksum> checksumsMap = null;
+        if (!checksums.isEmpty()) {
+            checksumsMap = new ArrayMap<>(checksums.size());
+            for (int i = 0, isize = checksums.size(); i < isize; ++i) {
+                final String fileName = checksums.keyAt(i);
+                final List<Checksum> perFileChecksum = checksums.valueAt(i);
+                final byte[] perFileSignature = signatures.get(fileName);
+                checksumsMap.put(fileName, new PerFileChecksum(
+                        perFileChecksum.toArray(new Checksum[perFileChecksum.size()]),
+                        perFileSignature));
+            }
+        }
+
         InstallSource installSource = InstallSource.create(installInitiatingPackageName,
                 installOriginatingPackageName, installerPackageName, installerAttributionTag);
-        return new PackageInstallerSession(callback, context, pm, sessionProvider,
-                installerThread, stagingManager, sessionId, userId, installerUid,
-                installSource, params, createdMillis, committedMillis, stageDir, stageCid,
-                fileArray, checksums, prepared, committed, destroyed, sealed, childSessionIdsArray,
-                parentSessionId, isReady, isFailed, isApplied, stagedSessionErrorCode,
-                stagedSessionErrorMessage);
+        return new PackageInstallerSession(callback, context, pm, sessionProvider, installerThread,
+                stagingManager, sessionId, userId, installerUid, installSource, params,
+                createdMillis, committedMillis, stageDir, stageCid, fileArray, checksumsMap,
+                prepared, committed, destroyed, sealed, childSessionIdsArray, parentSessionId,
+                isReady, isFailed, isApplied, stagedSessionErrorCode, stagedSessionErrorMessage);
     }
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index de7338f..c93127d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -464,7 +464,7 @@
 /**
  * Keep track of all those APKs everywhere.
  * <p>
- * Internally there are two important locks:
+ * Internally there are three important locks:
  * <ul>
  * <li>{@link #mLock} is used to guard all in-memory parsed package details
  * and other related state. It is a fine-grained lock that should only be held
@@ -475,6 +475,10 @@
  * this lock should never be acquired while already holding {@link #mLock}.
  * Conversely, it's safe to acquire {@link #mLock} momentarily while already
  * holding {@link #mInstallLock}.
+ * <li>{@link #mSnapshotLock} is used to guard access to two snapshot fields: the snapshot
+ * itself and the snapshot invalidation flag.  This lock should never be acquired while
+ * already holding {@link #mLock}. Conversely, it's safe to acquire {@link #mLock}
+ * momentarily while already holding {@link #mSnapshotLock}.
  * </ul>
  * Many internal methods rely on the caller to hold the appropriate locks, and
  * this contract is expressed through method name suffixes:
@@ -485,6 +489,8 @@
  * <li>fooLPr(): the caller must hold {@link #mLock} for reading
  * <li>fooLPw(): the caller must hold {@link #mLock} for writing
  * </ul>
+ * {@link #mSnapshotLock} is taken in exactly one place - {@code snapshotComputer()}.  It
+ * should not be taken anywhere else or used for any other purpose.
  * <p>
  * Because this class is very central to the platform's security; please run all
  * CTS and unit tests whenever making modifications:
@@ -4727,11 +4733,19 @@
     // If true, the cached computer object is invalid (the cache is stale).
     // The attribute is static since it may be set from outside classes.
     private static volatile boolean sSnapshotInvalid = true;
-     // If true, the cache is corked.  Do not create a new cache but continue to use the
+    // If true, the cache is corked.  Do not create a new cache but continue to use the
     // existing one.  This throttles cache creation during periods of churn in Package
     // Manager.
     private static volatile boolean sSnapshotCorked = false;
 
+    /**
+     * This lock is used to make reads from {@link #sSnapshotInvalid} and
+     * {@link #mSnapshotComputer} atomic inside {@code snapshotComputer()}.  This lock is
+     * not meant to be used outside that method.  This lock must be taken before
+     * {@link #mLock} is taken.
+     */
+    private final Object mSnapshotLock = new Object();
+
     // A counter of all queries that hit the cache.
     private AtomicInteger mSnapshotHits = new AtomicInteger(0);
 
@@ -4759,35 +4773,42 @@
         if (!SNAPSHOT_ENABLED) {
             return mLiveComputer;
         }
+        if (Thread.holdsLock(mLock)) {
+            // If the current thread holds mLock then it may have modified state but not
+            // yet invalidated the snapshot.  Always give the thread the live computer.
+            return mLiveComputer;
+        }
         int hits = 0;
         if (TRACE_CACHES) {
             hits = mSnapshotHits.incrementAndGet();
         }
-        Computer c = mSnapshotComputer;
-        if (sSnapshotCorked && (c != null)) {
-            // Snapshots are corked, which means new ones should not be built right now.
+        synchronized (mSnapshotLock) {
+            Computer c = mSnapshotComputer;
+            if (sSnapshotCorked && (c != null)) {
+                // Snapshots are corked, which means new ones should not be built right now.
+                return c;
+            }
+            if (sSnapshotInvalid || (c == null)) {
+                // The snapshot is invalid if it is marked as invalid or if it is null.  If it
+                // is null, then it is currently being rebuilt by rebuildSnapshot().
+                synchronized (mLock) {
+                    // Rebuild the snapshot if it is invalid.  Note that the snapshot might be
+                    // invalidated as it is rebuilt.  However, the snapshot is still
+                    // self-consistent (the lock is being held)and is current as of the time
+                    // this function is entered.
+                    if (sSnapshotInvalid) {
+                        rebuildSnapshot(hits);
+                    }
+
+                    // Guaranteed to be non-null.  mSnapshotComputer is only be set to null
+                    // temporarily in rebuildSnapshot(), which is guarded by mLock().  Since
+                    // the mLock is held in this block and since rebuildSnapshot() is
+                    // complete, the attribute can not now be null.
+                    c = mSnapshotComputer;
+                }
+            }
             return c;
         }
-        if (sSnapshotInvalid || (c == null)) {
-            // The snapshot is invalid if it is marked as invalid or if it is null.  If it
-            // is null, then it is currently being rebuilt by rebuildSnapshot().
-            synchronized (mLock) {
-                // Rebuild the snapshot if it is invalid.  Note that the snapshot might be
-                // invalidated as it is rebuilt.  However, the snapshot is still
-                // self-consistent (the lock is being held)and is current as of the time
-                // this function is entered.
-                if (sSnapshotInvalid) {
-                    rebuildSnapshot(hits);
-                }
-
-                // Guaranteed to be non-null.  mSnapshotComputer is only be set to null
-                // temporarily in rebuildSnapshot(), which is guarded by mLock().  Since
-                // the mLock is held in this block and since rebuildSnapshot() is
-                // complete, the attribute can not now be null.
-                c = mSnapshotComputer;
-            }
-        }
-        return c;
     }
 
     /**
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 9f07695..89729b5 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -1049,6 +1049,7 @@
                             }
                         }
 
+                        // TODO: update resource strings in AppSearch
                         // If this shortcut is not from a manifest, then update all resource IDs
                         // from resource names.  (We don't allow resource strings for
                         // non-manifest at the moment, but icons can still be resources.)
@@ -1340,6 +1341,7 @@
      * For all the text fields, refresh the string values if they're from resources.
      */
     public void resolveResourceStrings() {
+        // TODO: update resource strings in AppSearch
         final ShortcutService s = mShortcutUser.mService;
 
         List<ShortcutInfo> changedShortcuts = null;
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 95ce140..3c4457d 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -1565,6 +1565,7 @@
      * resource-based strings.
      */
     void fixUpShortcutResourceNamesAndValues(ShortcutInfo si) {
+        // TODO: update resource names in AppSearch
         final Resources publisherRes = injectGetResourcesForApplicationAsUser(
                 si.getPackage(), si.getUserId());
         if (publisherRes != null) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 7caf739..607c165 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -39,6 +39,7 @@
 import static android.view.KeyEvent.KEYCODE_BACK;
 import static android.view.KeyEvent.KEYCODE_DPAD_CENTER;
 import static android.view.KeyEvent.KEYCODE_DPAD_DOWN;
+import static android.view.KeyEvent.KEYCODE_HOME;
 import static android.view.KeyEvent.KEYCODE_POWER;
 import static android.view.KeyEvent.KEYCODE_UNKNOWN;
 import static android.view.KeyEvent.KEYCODE_VOLUME_DOWN;
@@ -490,6 +491,7 @@
     boolean mWakeOnDpadKeyPress;
     boolean mWakeOnAssistKeyPress;
     boolean mWakeOnBackKeyPress;
+    long mWakeUpToLastStateTimeout;
 
     private boolean mHandleVolumeKeysInWM;
 
@@ -1846,6 +1848,9 @@
         mPerDisplayFocusEnabled = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_perDisplayFocusEnabled);
 
+        mWakeUpToLastStateTimeout = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_wakeUpToLastStateTimeoutMillis);
+
         readConfigurationDependentBehaviors();
 
         mDisplayFoldController = DisplayFoldController.create(context, DEFAULT_DISPLAY);
@@ -2600,7 +2605,7 @@
         // can never break it, although if keyguard is on, we do let
         // it handle it, because that gives us the correct 5 second
         // timeout.
-        if (keyCode == KeyEvent.KEYCODE_HOME) {
+        if (keyCode == KEYCODE_HOME) {
             DisplayHomeButtonHandler handler = mDisplayHomeButtonHandlers.get(displayId);
             if (handler == null) {
                 handler = new DisplayHomeButtonHandler(displayId);
@@ -3556,8 +3561,7 @@
         if (isValidGlobalKey(keyCode)
                 && mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) {
             if (isWakeKey) {
-                wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey,
-                        PowerManager.WAKE_REASON_WAKE_KEY, "android.policy:KEY");
+                wakeUpFromWakeKey(event);
             }
             return result;
         }
@@ -3879,8 +3883,7 @@
         }
 
         if (isWakeKey) {
-            wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey,
-                    PowerManager.WAKE_REASON_WAKE_KEY, "android.policy:KEY");
+            wakeUpFromWakeKey(event);
         }
 
         if ((result & ACTION_PASS_TO_USER) != 0) {
@@ -4319,9 +4322,39 @@
         }
     }
 
+    private boolean shouldWakeUpWithHomeIntent() {
+        if (mWakeUpToLastStateTimeout <= 0) {
+            return false;
+        }
+
+        final long sleepDuration = mPowerManagerInternal.getLastWakeup().sleepDuration;
+        if (DEBUG_WAKEUP) {
+            Log.i(TAG, "shouldWakeUpWithHomeIntent: sleepDuration= " + sleepDuration
+                    + " mWakeUpToLastStateTimeout= " + mWakeUpToLastStateTimeout);
+        }
+        return sleepDuration > mWakeUpToLastStateTimeout;
+    }
+
     private void wakeUpFromPowerKey(long eventTime) {
-        wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey,
-                PowerManager.WAKE_REASON_POWER_BUTTON, "android.policy:POWER");
+        if (wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey,
+                PowerManager.WAKE_REASON_POWER_BUTTON, "android.policy:POWER")) {
+            // Start HOME with "reason" extra if sleeping for more than mWakeUpToLastStateTimeout
+            if (shouldWakeUpWithHomeIntent()) {
+                startDockOrHome(DEFAULT_DISPLAY, /*fromHomeKey*/ false, /*wakenFromDreams*/ true,
+                        PowerManager.wakeReasonToString(PowerManager.WAKE_REASON_POWER_BUTTON));
+            }
+        }
+    }
+
+    private void wakeUpFromWakeKey(KeyEvent event) {
+        if (wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey,
+                PowerManager.WAKE_REASON_WAKE_KEY, "android.policy:KEY")) {
+            // Start HOME with "reason" extra if sleeping for more than mWakeUpToLastStateTimeout
+            if (shouldWakeUpWithHomeIntent() && event.getKeyCode() == KEYCODE_HOME) {
+                startDockOrHome(DEFAULT_DISPLAY, /*fromHomeKey*/ true, /*wakenFromDreams*/ true,
+                        PowerManager.wakeReasonToString(PowerManager.WAKE_REASON_WAKE_KEY));
+            }
+        }
     }
 
     private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode, @WakeReason int reason,
@@ -5004,7 +5037,8 @@
         return null;
     }
 
-    void startDockOrHome(int displayId, boolean fromHomeKey, boolean awakenFromDreams) {
+    void startDockOrHome(int displayId, boolean fromHomeKey, boolean awakenFromDreams,
+            String startReason) {
         try {
             ActivityManager.getService().stopAppSwitches();
         } catch (RemoteException e) {}
@@ -5032,11 +5066,20 @@
             }
         }
 
+        if (DEBUG_WAKEUP) {
+            Log.d(TAG, "startDockOrHome: startReason= " + startReason);
+        }
+
         // Start home.
-        mActivityTaskManagerInternal.startHomeOnDisplay(mCurrentUserId, "startDockOrHome",
+        mActivityTaskManagerInternal.startHomeOnDisplay(mCurrentUserId, startReason,
                 displayId, true /* allowInstrumenting */, fromHomeKey);
     }
 
+    void startDockOrHome(int displayId, boolean fromHomeKey, boolean awakenFromDreams) {
+        startDockOrHome(displayId, fromHomeKey, awakenFromDreams, /*startReason*/
+                "startDockOrHome");
+    }
+
     /**
      * goes to the home screen
      * @return whether it did anything
diff --git a/services/core/java/com/android/server/policy/WindowOrientationListener.java b/services/core/java/com/android/server/policy/WindowOrientationListener.java
index 0157706..17e81da 100644
--- a/services/core/java/com/android/server/policy/WindowOrientationListener.java
+++ b/services/core/java/com/android/server/policy/WindowOrientationListener.java
@@ -62,6 +62,7 @@
     private Sensor mSensor;
     private OrientationJudge mOrientationJudge;
     private int mCurrentRotation = -1;
+    private final Context mContext;
 
     private final Object mLock = new Object();
 
@@ -88,6 +89,7 @@
      * This constructor is private since no one uses it.
      */
     private WindowOrientationListener(Context context, Handler handler, int rate) {
+        mContext = context;
         mHandler = handler;
         mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
         mRate = rate;
@@ -284,6 +286,19 @@
         }
     }
 
+    /**
+     * Returns whether this WindowOrientationListener can remain enabled while the device is dozing.
+     * If this returns true, it implies that the underlying sensor can still run while the AP is
+     * asleep, and that the underlying sensor will wake the AP on an event.
+     */
+    public boolean shouldStayEnabledWhileDreaming() {
+        if (mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_forceOrientationListenerEnabledWhileDreaming)) {
+            return true;
+        }
+        return mSensor.getType() == Sensor.TYPE_DEVICE_ORIENTATION && mSensor.isWakeUpSensor();
+    }
+
     abstract class OrientationJudge implements SensorEventListener {
         // Number of nanoseconds per millisecond.
         protected static final long NANOS_PER_MS = 1000000;
diff --git a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
deleted file mode 100644
index b95c5efc..0000000
--- a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
+++ /dev/null
@@ -1,171 +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.
- */
-
-package com.android.server.policy.role;
-
-import android.annotation.NonNull;
-import android.annotation.UserIdInt;
-import android.app.role.RoleManager;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
-import android.content.pm.ResolveInfo;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.Slog;
-
-import com.android.internal.R;
-import com.android.internal.telephony.SmsApplication;
-import com.android.internal.util.CollectionUtils;
-import com.android.server.LocalServices;
-import com.android.server.role.LegacyRoleHolderProvider;
-import com.android.server.role.RoleManagerService;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Logic to retrieve the various legacy(pre-Q) equivalents of role holders.
- *
- * Unlike {@link RoleManagerService} this is meant to be pretty high-level to allow for depending
- * on all kinds of various systems that are historically involved in legacy role resolution,
- * e.g. {@link SmsApplication}
- *
- * @see RoleManagerService#migrateRoleIfNecessary
- */
-public class LegacyRoleResolutionPolicy implements LegacyRoleHolderProvider {
-
-    private static final boolean DEBUG = false;
-    private static final String LOG_TAG = "LegacyRoleResolutionPol";
-
-    @NonNull
-    private final Context mContext;
-
-    public LegacyRoleResolutionPolicy(@NonNull Context context) {
-        mContext = context;
-    }
-
-    @NonNull
-    @Override
-    public List<String> getLegacyRoleHolders(@NonNull String roleName, @UserIdInt int userId) {
-        switch (roleName) {
-            case RoleManager.ROLE_ASSISTANT: {
-                String packageName;
-                String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(),
-                        Settings.Secure.ASSISTANT, userId);
-                // AssistUtils was using the default assistant app if Settings.Secure.ASSISTANT is
-                // null, while only an empty string means user selected "None".
-                if (setting != null) {
-                    if (!setting.isEmpty()) {
-                        ComponentName componentName = ComponentName.unflattenFromString(setting);
-                        packageName = componentName != null ? componentName.getPackageName() : null;
-                    } else {
-                        packageName = null;
-                    }
-                } else if (mContext.getPackageManager().isDeviceUpgrading()) {
-                    String defaultAssistant = mContext.getString(R.string.config_defaultAssistant);
-                    packageName = !TextUtils.isEmpty(defaultAssistant) ? defaultAssistant : null;
-                } else {
-                    packageName = null;
-                }
-                return CollectionUtils.singletonOrEmpty(packageName);
-            }
-            case RoleManager.ROLE_BROWSER: {
-                PackageManagerInternal packageManagerInternal = LocalServices.getService(
-                        PackageManagerInternal.class);
-                String packageName = packageManagerInternal.removeLegacyDefaultBrowserPackageName(
-                        userId);
-                return CollectionUtils.singletonOrEmpty(packageName);
-            }
-            case RoleManager.ROLE_DIALER: {
-                String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(),
-                        Settings.Secure.DIALER_DEFAULT_APPLICATION, userId);
-                String packageName;
-                if (!TextUtils.isEmpty(setting)) {
-                    packageName = setting;
-                } else if (mContext.getPackageManager().isDeviceUpgrading()) {
-                    // DefaultDialerManager was using the default dialer app if
-                    // Settings.Secure.DIALER_DEFAULT_APPLICATION is invalid.
-                    // TelecomManager.getSystemDialerPackage() won't work because it might not
-                    // be ready.
-                    packageName = mContext.getString(R.string.config_defaultDialer);
-                } else {
-                    packageName = null;
-                }
-                return CollectionUtils.singletonOrEmpty(packageName);
-            }
-            case RoleManager.ROLE_SMS: {
-                String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(),
-                        Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
-                String packageName;
-                if (!TextUtils.isEmpty(setting)) {
-                    packageName = setting;
-                } else if (mContext.getPackageManager().isDeviceUpgrading()) {
-                    // SmsApplication was using the default SMS app if
-                    // Settings.Secure.DIALER_DEFAULT_APPLICATION is invalid.
-                    packageName = mContext.getString(R.string.config_defaultSms);
-                } else {
-                    packageName = null;
-                }
-                return CollectionUtils.singletonOrEmpty(packageName);
-            }
-            case RoleManager.ROLE_HOME: {
-                PackageManager packageManager = mContext.getPackageManager();
-                String packageName;
-                if (packageManager.isDeviceUpgrading()) {
-                    ResolveInfo resolveInfo = packageManager.resolveActivityAsUser(
-                            new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME),
-                            PackageManager.MATCH_DEFAULT_ONLY
-                                    | PackageManager.MATCH_DIRECT_BOOT_AWARE
-                                    | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
-                    packageName = resolveInfo != null && resolveInfo.activityInfo != null
-                            ? resolveInfo.activityInfo.packageName : null;
-                    if (packageName != null && isSettingsApplication(packageName, userId)) {
-                        packageName = null;
-                    }
-                } else {
-                    packageName = null;
-                }
-                return CollectionUtils.singletonOrEmpty(packageName);
-            }
-            case RoleManager.ROLE_EMERGENCY: {
-                String defaultEmergencyApp = Settings.Secure.getStringForUser(
-                        mContext.getContentResolver(),
-                        Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION, userId);
-                return CollectionUtils.singletonOrEmpty(defaultEmergencyApp);
-            }
-            default: {
-                Slog.e(LOG_TAG, "Don't know how to find legacy role holders for " + roleName);
-                return Collections.emptyList();
-            }
-        }
-    }
-
-    private boolean isSettingsApplication(@NonNull String packageName, @UserIdInt int userId) {
-        PackageManager packageManager = mContext.getPackageManager();
-        ResolveInfo resolveInfo = packageManager.resolveActivityAsUser(new Intent(
-                Settings.ACTION_SETTINGS), PackageManager.MATCH_DEFAULT_ONLY
-                | PackageManager.MATCH_DIRECT_BOOT_AWARE
-                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
-        if (resolveInfo == null || resolveInfo.activityInfo == null) {
-            return false;
-        }
-        return Objects.equals(packageName, resolveInfo.activityInfo.packageName);
-    }
-}
diff --git a/services/core/java/com/android/server/policy/role/LegacyRoleStateProviderImpl.java b/services/core/java/com/android/server/policy/role/LegacyRoleStateProviderImpl.java
new file mode 100644
index 0000000..097f332
--- /dev/null
+++ b/services/core/java/com/android/server/policy/role/LegacyRoleStateProviderImpl.java
@@ -0,0 +1,291 @@
+/*
+ * 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.
+ */
+
+package com.android.server.policy.role;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.role.RoleManager;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.ResolveInfo;
+import android.os.Environment;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.internal.R;
+import com.android.server.LocalServices;
+import com.android.server.role.LegacyRoleStateProvider;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Implementation to provide legacy role state.
+ */
+public class LegacyRoleStateProviderImpl implements LegacyRoleStateProvider {
+    private static final String LOG_TAG = "LegacyRoleState";
+
+    private static final String ROLES_FILE_NAME = "roles.xml";
+
+    private static final String TAG_ROLES = "roles";
+    private static final String TAG_ROLE = "role";
+    private static final String TAG_HOLDER = "holder";
+    private static final String ATTRIBUTE_NAME = "name";
+
+    @NonNull
+    private final Context mContext;
+
+    public LegacyRoleStateProviderImpl(@NonNull Context context) {
+        mContext = context;
+    }
+
+    @NonNull
+    @Override
+    public Map<String, Set<String>> getLegacyRoleState(@UserIdInt int userId) {
+        Map<String, Set<String>> roles = readFile(userId);
+        if (roles == null) {
+            roles = readFromLegacySettings(userId);
+        }
+        return roles;
+    }
+
+    @Nullable
+    private Map<String, Set<String>> readFile(@UserIdInt int userId) {
+        File file = getFile(userId);
+        try (FileInputStream in = new AtomicFile(file).openRead()) {
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(in, null);
+            Map<String, Set<String>> roles = parseXml(parser);
+            Slog.i(LOG_TAG, "Read legacy roles.xml successfully");
+            return roles;
+        } catch (FileNotFoundException e) {
+            Slog.i(LOG_TAG, "Legacy roles.xml not found");
+            return null;
+        } catch (XmlPullParserException | IOException e) {
+            Slog.wtf(LOG_TAG, "Failed to parse legacy roles.xml: " + file, e);
+            return null;
+        }
+    }
+
+    @NonNull
+    private Map<String, Set<String>> parseXml(@NonNull XmlPullParser parser) throws IOException,
+            XmlPullParserException {
+        int type;
+        int depth;
+        int innerDepth = parser.getDepth() + 1;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
+            if (depth > innerDepth || type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            if (parser.getName().equals(TAG_ROLES)) {
+                return parseRoles(parser);
+            }
+        }
+
+        throw new IOException("Missing <" + TAG_ROLES + "> in roles.xml");
+    }
+
+    @NonNull
+    private Map<String, Set<String>> parseRoles(@NonNull XmlPullParser parser) throws IOException,
+            XmlPullParserException {
+        Map<String, Set<String>> roles = new ArrayMap<>();
+
+        int type;
+        int depth;
+        int innerDepth = parser.getDepth() + 1;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
+            if (depth > innerDepth || type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            if (parser.getName().equals(TAG_ROLE)) {
+                String roleName = parser.getAttributeValue(null, ATTRIBUTE_NAME);
+                Set<String> roleHolders = parseRoleHoldersLocked(parser);
+                roles.put(roleName, roleHolders);
+            }
+        }
+
+        return roles;
+    }
+
+    @NonNull
+    private Set<String> parseRoleHoldersLocked(@NonNull XmlPullParser parser)
+            throws IOException, XmlPullParserException {
+        Set<String> roleHolders = new ArraySet<>();
+
+        int type;
+        int depth;
+        int innerDepth = parser.getDepth() + 1;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
+            if (depth > innerDepth || type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            if (parser.getName().equals(TAG_HOLDER)) {
+                String roleHolder = parser.getAttributeValue(null, ATTRIBUTE_NAME);
+                roleHolders.add(roleHolder);
+            }
+        }
+
+        return roleHolders;
+    }
+
+    @NonNull
+    private static File getFile(@UserIdInt int userId) {
+        return new File(Environment.getUserSystemDirectory(userId), ROLES_FILE_NAME);
+    }
+
+    @NonNull
+    private Map<String, Set<String>> readFromLegacySettings(@UserIdInt int userId) {
+        Map<String, Set<String>> roles = new ArrayMap<>();
+
+        // Assistant
+        ContentResolver contentResolver = mContext.getContentResolver();
+        String assistantSetting = Settings.Secure.getStringForUser(contentResolver,
+                Settings.Secure.ASSISTANT, userId);
+        PackageManager packageManager = mContext.getPackageManager();
+        String assistantPackageName;
+        // AssistUtils was using the default assistant app if Settings.Secure.ASSISTANT is
+        // null, while only an empty string means user selected "None".
+        if (assistantSetting != null) {
+            if (!assistantSetting.isEmpty()) {
+                ComponentName componentName = ComponentName.unflattenFromString(assistantSetting);
+                assistantPackageName = componentName != null ? componentName.getPackageName()
+                        : null;
+            } else {
+                assistantPackageName = null;
+            }
+        } else if (packageManager.isDeviceUpgrading()) {
+            String defaultAssistant = mContext.getString(R.string.config_defaultAssistant);
+            assistantPackageName = !TextUtils.isEmpty(defaultAssistant) ? defaultAssistant : null;
+        } else {
+            assistantPackageName = null;
+        }
+        if (assistantPackageName != null) {
+            roles.put(RoleManager.ROLE_ASSISTANT, Collections.singleton(assistantPackageName));
+        }
+
+        // Browser
+        PackageManagerInternal packageManagerInternal = LocalServices.getService(
+                PackageManagerInternal.class);
+        String browserPackageName = packageManagerInternal.removeLegacyDefaultBrowserPackageName(
+                userId);
+        if (browserPackageName != null) {
+            roles.put(RoleManager.ROLE_BROWSER, Collections.singleton(browserPackageName));
+        }
+
+        // Dialer
+        String dialerSetting = Settings.Secure.getStringForUser(contentResolver,
+                Settings.Secure.DIALER_DEFAULT_APPLICATION, userId);
+        String dialerPackageName;
+        if (!TextUtils.isEmpty(dialerSetting)) {
+            dialerPackageName = dialerSetting;
+        } else if (packageManager.isDeviceUpgrading()) {
+            // DefaultDialerManager was using the default dialer app if
+            // Settings.Secure.DIALER_DEFAULT_APPLICATION is invalid.
+            // TelecomManager.getSystemDialerPackage() won't work because it might not
+            // be ready.
+            dialerPackageName = mContext.getString(R.string.config_defaultDialer);
+        } else {
+            dialerPackageName = null;
+        }
+        if (dialerPackageName != null) {
+            roles.put(RoleManager.ROLE_DIALER, Collections.singleton(dialerPackageName));
+        }
+
+        // SMS
+        String smsSetting = Settings.Secure.getStringForUser(contentResolver,
+                Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
+        String smsPackageName;
+        if (!TextUtils.isEmpty(smsSetting)) {
+            smsPackageName = smsSetting;
+        } else if (mContext.getPackageManager().isDeviceUpgrading()) {
+            // SmsApplication was using the default SMS app if
+            // Settings.Secure.DIALER_DEFAULT_APPLICATION is invalid.
+            smsPackageName = mContext.getString(R.string.config_defaultSms);
+        } else {
+            smsPackageName = null;
+        }
+        if (smsPackageName != null) {
+            roles.put(RoleManager.ROLE_SMS, Collections.singleton(smsPackageName));
+        }
+
+        // Home
+        String homePackageName;
+        if (packageManager.isDeviceUpgrading()) {
+            ResolveInfo resolveInfo = packageManager.resolveActivityAsUser(
+                    new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME),
+                    PackageManager.MATCH_DEFAULT_ONLY
+                            | PackageManager.MATCH_DIRECT_BOOT_AWARE
+                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
+            homePackageName = resolveInfo != null && resolveInfo.activityInfo != null
+                    ? resolveInfo.activityInfo.packageName : null;
+            if (homePackageName != null && isSettingsApplication(homePackageName, userId)) {
+                homePackageName = null;
+            }
+        } else {
+            homePackageName = null;
+        }
+        if (homePackageName != null) {
+            roles.put(RoleManager.ROLE_HOME, Collections.singleton(homePackageName));
+        }
+
+        // Emergency
+        String emergencyPackageName = Settings.Secure.getStringForUser(contentResolver,
+                Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION, userId);
+        if (emergencyPackageName != null) {
+            roles.put(RoleManager.ROLE_EMERGENCY, Collections.singleton(emergencyPackageName));
+        }
+
+        return roles;
+    }
+
+    private boolean isSettingsApplication(@NonNull String packageName, @UserIdInt int userId) {
+        PackageManager packageManager = mContext.getPackageManager();
+        ResolveInfo resolveInfo = packageManager.resolveActivityAsUser(new Intent(
+                Settings.ACTION_SETTINGS), PackageManager.MATCH_DEFAULT_ONLY
+                | PackageManager.MATCH_DIRECT_BOOT_AWARE
+                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
+        if (resolveInfo == null || resolveInfo.activityInfo == null) {
+            return false;
+        }
+        return Objects.equals(packageName, resolveInfo.activityInfo.packageName);
+    }
+}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 955e1cd..084dc32 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -5570,7 +5570,7 @@
 
     private PowerManager.WakeData getLastWakeupInternal() {
         synchronized (mLock) {
-            return new WakeData(mLastWakeTime, mLastWakeReason);
+            return new WakeData(mLastWakeTime, mLastWakeReason, mLastWakeTime - mLastSleepTime);
         }
     }
 
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsService.java b/services/core/java/com/android/server/powerstats/PowerStatsService.java
index 7778572..64bddcd 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsService.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsService.java
@@ -19,14 +19,19 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.hardware.power.stats.ChannelInfo;
+import android.hardware.power.stats.EnergyConsumerResult;
 import android.hardware.power.stats.PowerEntityInfo;
 import android.os.Binder;
 import android.os.Environment;
+import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.UserHandle;
+import android.power.PowerStatsInternal;
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.DumpUtils;
+import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.SystemService;
 import com.android.server.powerstats.PowerStatsHALWrapper.IPowerStatsHALWrapper;
 import com.android.server.powerstats.ProtoStreamUtils.ChannelInfoUtils;
@@ -36,6 +41,7 @@
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.concurrent.CompletableFuture;
 
 /**
  * This class provides a system service that estimates system power usage
@@ -55,7 +61,6 @@
     private final Injector mInjector;
 
     private Context mContext;
-    private IPowerStatsHALWrapper mPowerStatsHALWrapper;
     @Nullable
     private PowerStatsLogger mPowerStatsLogger;
     @Nullable
@@ -65,6 +70,8 @@
 
     @VisibleForTesting
     static class Injector {
+        private IPowerStatsHALWrapper mPowerStatsHALWrapper;
+
         File createDataStoragePath() {
             return new File(Environment.getDataSystemDeDirectory(UserHandle.USER_SYSTEM),
                 DATA_STORAGE_SUBDIR);
@@ -86,6 +93,13 @@
             return PowerStatsHALWrapper.getPowerStatsHalImpl();
         }
 
+        IPowerStatsHALWrapper getPowerStatsHALWrapperImpl() {
+            if (mPowerStatsHALWrapper == null) {
+                mPowerStatsHALWrapper = PowerStatsHALWrapper.getPowerStatsHalImpl();
+            }
+            return mPowerStatsHALWrapper;
+        }
+
         PowerStatsLogger createPowerStatsLogger(Context context, File dataStoragePath,
                 String meterFilename, String modelFilename, String residencyFilename,
                 IPowerStatsHALWrapper powerStatsHALWrapper) {
@@ -120,15 +134,15 @@
                     }
                 } else if (args.length == 0) {
                     pw.println("PowerStatsService dumpsys: available PowerEntityInfos");
-                    PowerEntityInfo[] powerEntityInfo = mPowerStatsHALWrapper.getPowerEntityInfo();
+                    PowerEntityInfo[] powerEntityInfo = getPowerStatsHal().getPowerEntityInfo();
                     PowerEntityInfoUtils.dumpsys(powerEntityInfo, pw);
 
                     pw.println("PowerStatsService dumpsys: available ChannelInfos");
-                    ChannelInfo[] channelInfo = mPowerStatsHALWrapper.getEnergyMeterInfo();
+                    ChannelInfo[] channelInfo = getPowerStatsHal().getEnergyMeterInfo();
                     ChannelInfoUtils.dumpsys(channelInfo, pw);
 
                     pw.println("PowerStatsService dumpsys: available EnergyConsumerIds");
-                    int[] energyConsumerId = mPowerStatsHALWrapper.getEnergyConsumerInfo();
+                    int[] energyConsumerId = getPowerStatsHal().getEnergyConsumerInfo();
                     EnergyConsumerIdUtils.dumpsys(energyConsumerId, pw);
                 }
             }
@@ -144,27 +158,33 @@
 
     @Override
     public void onStart() {
+        if (getPowerStatsHal().isInitialized()) {
+            // Only create internal service if PowerStatsHal is available.
+            publishLocalService(PowerStatsInternal.class, new LocalService());
+        }
         publishBinderService(Context.POWER_STATS_SERVICE, new BinderService());
     }
 
     private void onSystemServiceReady() {
-        mPowerStatsHALWrapper = mInjector.createPowerStatsHALWrapperImpl();
-
-        if (mPowerStatsHALWrapper.isInitialized()) {
-            if (DEBUG) Slog.d(TAG, "Starting PowerStatsService");
+        if (getPowerStatsHal().isInitialized()) {
+            if (DEBUG) Slog.d(TAG, "Starting PowerStatsService loggers");
 
             // Only start logger and triggers if initialization is successful.
             mPowerStatsLogger = mInjector.createPowerStatsLogger(mContext,
                 mInjector.createDataStoragePath(), mInjector.createMeterFilename(),
                 mInjector.createModelFilename(), mInjector.createResidencyFilename(),
-                mPowerStatsHALWrapper);
+                getPowerStatsHal());
             mBatteryTrigger = mInjector.createBatteryTrigger(mContext, mPowerStatsLogger);
             mTimerTrigger = mInjector.createTimerTrigger(mContext, mPowerStatsLogger);
         } else {
-            Slog.e(TAG, "Initialization of PowerStatsHAL wrapper failed");
+            Slog.e(TAG, "Failed to start PowerStatsService loggers");
         }
     }
 
+    private IPowerStatsHALWrapper getPowerStatsHal() {
+        return mInjector.getPowerStatsHALWrapperImpl();
+    }
+
     public PowerStatsService(Context context) {
         this(context, new Injector());
     }
@@ -175,4 +195,29 @@
         mContext = context;
         mInjector = injector;
     }
+
+    private final class LocalService extends PowerStatsInternal {
+        private final Handler mHandler;
+
+        LocalService() {
+            HandlerThread thread = new HandlerThread(TAG);
+            thread.start();
+            mHandler = new Handler(thread.getLooper());
+        }
+
+        @Override
+        public CompletableFuture<EnergyConsumerResult[]> getEnergyConsumedAsync(
+                int[] energyConsumerIds) {
+            final CompletableFuture<EnergyConsumerResult[]> future = new CompletableFuture<>();
+            mHandler.sendMessage(
+                    PooledLambda.obtainMessage(PowerStatsService.this::getEnergyConsumedAsync,
+                            future, energyConsumerIds));
+            return future;
+        }
+    }
+
+    private void getEnergyConsumedAsync(CompletableFuture<EnergyConsumerResult[]> future,
+            int[] energyConsumerIds) {
+        future.complete(getPowerStatsHal().getEnergyConsumed(energyConsumerIds));
+    }
 }
diff --git a/services/core/java/com/android/server/role/LegacyRoleHolderProvider.java b/services/core/java/com/android/server/role/LegacyRoleHolderProvider.java
deleted file mode 100644
index ed0d675..0000000
--- a/services/core/java/com/android/server/role/LegacyRoleHolderProvider.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.role;
-
-import android.annotation.NonNull;
-import android.annotation.UserIdInt;
-
-import java.util.List;
-
-/**
- * A provider for migrating legacy "role"s to their actual role implementation.
- */
-//@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
-public interface LegacyRoleHolderProvider {
-    /**
-     * Get the list of holders of a legacy "role" before its actual role is introduced.
-     * <p>
-     * This method will only be called for the first time a role is made available in the platform.
-     *
-     * @param roleName the name of the role
-     * @param userId the user ID
-     * @return a list of holders for the given role
-     */
-    @NonNull
-    List<String> getLegacyRoleHolders(@NonNull String roleName, @UserIdInt int userId);
-}
diff --git a/services/core/java/com/android/server/role/LegacyRoleStateProvider.java b/services/core/java/com/android/server/role/LegacyRoleStateProvider.java
new file mode 100644
index 0000000..ec4cfc1
--- /dev/null
+++ b/services/core/java/com/android/server/role/LegacyRoleStateProvider.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.role;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Provider for legacy role state.
+ * <p>
+ * The role state may come from two sources, either the different pre-role default app settings, or
+ * the pre-modularization roles.xml file stored in platform.
+ *
+ * @hide
+ */
+//@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+public interface LegacyRoleStateProvider {
+    /**
+     * Get the legacy role state stored in the platform.
+     *
+     * @param userId the user ID
+     * @return a mapping of role name to its set of holders
+     */
+    @NonNull
+    Map<String, Set<String>> getLegacyRoleState(@UserIdInt int userId);
+}
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index 4e42f16..bc5ddd3 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -103,7 +103,7 @@
     private final Object mLock = new Object();
 
     @NonNull
-    private final LegacyRoleHolderProvider mLegacyRoleHolderProvider;
+    private final LegacyRoleStateProvider mLegacyRoleStateProvider;
 
     /**
      * Maps user id to its state.
@@ -139,10 +139,10 @@
             new SparseArray<>();
 
     public RoleManagerService(@NonNull Context context,
-            @NonNull LegacyRoleHolderProvider legacyRoleHolderProvider) {
+            @NonNull LegacyRoleStateProvider legacyRoleStateProvider) {
         super(context);
 
-        mLegacyRoleHolderProvider = legacyRoleHolderProvider;
+        mLegacyRoleStateProvider = legacyRoleStateProvider;
 
         RoleControllerManager.initializeRemoteServiceComponentName(context);
 
@@ -241,16 +241,6 @@
             return AndroidFuture.completedFuture(null);
         }
 
-        //TODO gradually add more role migrations statements here for remaining roles
-        // Make sure to implement LegacyRoleResolutionPolicy#getRoleHolders
-        // for a given role before adding a migration statement for it here
-        maybeMigrateRole(RoleManager.ROLE_ASSISTANT, userId);
-        maybeMigrateRole(RoleManager.ROLE_BROWSER, userId);
-        maybeMigrateRole(RoleManager.ROLE_DIALER, userId);
-        maybeMigrateRole(RoleManager.ROLE_SMS, userId);
-        maybeMigrateRole(RoleManager.ROLE_EMERGENCY, userId);
-        maybeMigrateRole(RoleManager.ROLE_HOME, userId);
-
         // Some package state has changed, so grant default roles again.
         Slog.i(LOG_TAG, "Granting default roles...");
         AndroidFuture<Void> future = new AndroidFuture<>();
@@ -266,23 +256,6 @@
         return future;
     }
 
-    private void maybeMigrateRole(String role, @UserIdInt int userId) {
-        // Any role for which we have a record are already migrated
-        RoleUserState userState = getOrCreateUserState(userId);
-        if (!userState.isRoleAvailable(role)) {
-            List<String> roleHolders = mLegacyRoleHolderProvider.getLegacyRoleHolders(role, userId);
-            if (roleHolders.isEmpty()) {
-                return;
-            }
-            Slog.i(LOG_TAG, "Migrating " + role + ", legacy holders: " + roleHolders);
-            userState.addRoleName(role);
-            int size = roleHolders.size();
-            for (int i = 0; i < size; i++) {
-                userState.addRoleHolder(role, roleHolders.get(i));
-            }
-        }
-    }
-
     @Nullable
     private String computePackageStateHash(@UserIdInt int userId) {
         ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
@@ -327,7 +300,7 @@
         synchronized (mLock) {
             RoleUserState userState = mUserStates.get(userId);
             if (userState == null) {
-                userState = new RoleUserState(userId, this);
+                userState = new RoleUserState(userId, mLegacyRoleStateProvider, this);
                 mUserStates.put(userId, userState);
             }
             return userState;
@@ -663,7 +636,7 @@
                 getContext().enforceCallingOrSelfPermission(
                         android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
             }
-            if (mPackageManagerInternal.getInstantAppPackageName(callingUid) != null) {
+            if (isInstantApp(callingUid)) {
                 return null;
             }
 
@@ -676,6 +649,25 @@
             }
         }
 
+        private boolean isInstantApp(int uid) {
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                final UserHandle user = UserHandle.getUserHandleForUid(uid);
+                final Context userContext = getContext().createContextAsUser(user, 0);
+                final PackageManager userPackageManager = userContext.getPackageManager();
+                // Instant apps can not have shared UID, so it's safe to check only the first
+                // package name here.
+                final String packageName = ArrayUtils.firstOrNull(
+                        userPackageManager.getPackagesForUid(uid));
+                if (packageName == null) {
+                    return false;
+                }
+                return userPackageManager.isInstantApp(packageName);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
         @Override
         public boolean setBrowserRoleHolder(@Nullable String packageName, @UserIdInt int userId) {
             final Context context = getContext();
diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java
index 3a5ed5c..f5a79ea 100644
--- a/services/core/java/com/android/server/role/RoleUserState.java
+++ b/services/core/java/com/android/server/role/RoleUserState.java
@@ -21,14 +21,11 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.annotation.WorkerThread;
-import android.os.Environment;
 import android.os.Handler;
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.ArraySet;
-import android.util.AtomicFile;
 import android.util.Slog;
-import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.BackgroundThread;
@@ -38,13 +35,6 @@
 import com.android.role.persistence.RolesPersistence;
 import com.android.role.persistence.RolesState;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -59,23 +49,17 @@
 
     public static final int VERSION_UNDEFINED = -1;
 
-    private static final String ROLES_FILE_NAME = "roles.xml";
-
     private static final long WRITE_DELAY_MILLIS = 200;
 
-    private static final String TAG_ROLES = "roles";
-    private static final String TAG_ROLE = "role";
-    private static final String TAG_HOLDER = "holder";
-    private static final String ATTRIBUTE_VERSION = "version";
-    private static final String ATTRIBUTE_NAME = "name";
-    private static final String ATTRIBUTE_PACKAGES_HASH = "packagesHash";
-
     private final RolesPersistence mPersistence = RolesPersistence.createInstance();
 
     @UserIdInt
     private final int mUserId;
 
     @NonNull
+    private final LegacyRoleStateProvider mLegacyStateProvider;
+
+    @NonNull
     private final Callback mCallback;
 
     @NonNull
@@ -108,10 +92,13 @@
      * Create a new user state, and read its state from disk if previously persisted.
      *
      * @param userId the user id for this user state
+     * @param legacyStateProvider the provider for legacy role state
      * @param callback the callback for this user state
      */
-    public RoleUserState(@UserIdInt int userId, @NonNull Callback callback) {
+    public RoleUserState(@UserIdInt int userId,
+            @NonNull LegacyRoleStateProvider legacyStateProvider, @NonNull Callback callback) {
         mUserId = userId;
+        mLegacyStateProvider = legacyStateProvider;
         mCallback = callback;
 
         readFile();
@@ -368,102 +355,27 @@
 
     private void readFile() {
         synchronized (mLock) {
-            RolesState roles = mPersistence.readForUser(UserHandle.of(mUserId));
-            if (roles == null) {
-                readLegacyFileLocked();
-                scheduleWriteFileLocked();
-                return;
+            RolesState roleState = mPersistence.readForUser(UserHandle.of(mUserId));
+
+            Map<String, Set<String>> roles;
+            if (roleState != null) {
+                mVersion = roleState.getVersion();
+                mPackagesHash = roleState.getPackagesHash();
+                roles = roleState.getRoles();
+            } else {
+                roles = mLegacyStateProvider.getLegacyRoleState(mUserId);
             }
-
-            mVersion = roles.getVersion();
-            mPackagesHash = roles.getPackagesHash();
-
             mRoles.clear();
-            for (Map.Entry<String, Set<String>> entry : roles.getRoles().entrySet()) {
+            for (Map.Entry<String, Set<String>> entry : roles.entrySet()) {
                 String roleName = entry.getKey();
                 ArraySet<String> roleHolders = new ArraySet<>(entry.getValue());
                 mRoles.put(roleName, roleHolders);
             }
-        }
-    }
 
-    private void readLegacyFileLocked() {
-        File file = getFile(mUserId);
-        try (FileInputStream in = new AtomicFile(file).openRead()) {
-            XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(in, null);
-            parseXmlLocked(parser);
-            Slog.i(LOG_TAG, "Read roles.xml successfully");
-        } catch (FileNotFoundException e) {
-            Slog.i(LOG_TAG, "roles.xml not found");
-        } catch (XmlPullParserException | IOException e) {
-            throw new IllegalStateException("Failed to parse roles.xml: " + file, e);
-        }
-    }
-
-    private void parseXmlLocked(@NonNull XmlPullParser parser) throws IOException,
-            XmlPullParserException {
-        int type;
-        int depth;
-        int innerDepth = parser.getDepth() + 1;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
-            if (depth > innerDepth || type != XmlPullParser.START_TAG) {
-                continue;
-            }
-
-            if (parser.getName().equals(TAG_ROLES)) {
-                parseRolesLocked(parser);
-                return;
+            if (roleState == null) {
+                scheduleWriteFileLocked();
             }
         }
-        Slog.w(LOG_TAG, "Missing <" + TAG_ROLES + "> in roles.xml");
-    }
-
-    private void parseRolesLocked(@NonNull XmlPullParser parser) throws IOException,
-            XmlPullParserException {
-        mVersion = Integer.parseInt(parser.getAttributeValue(null, ATTRIBUTE_VERSION));
-        mPackagesHash = parser.getAttributeValue(null, ATTRIBUTE_PACKAGES_HASH);
-        mRoles.clear();
-
-        int type;
-        int depth;
-        int innerDepth = parser.getDepth() + 1;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
-            if (depth > innerDepth || type != XmlPullParser.START_TAG) {
-                continue;
-            }
-
-            if (parser.getName().equals(TAG_ROLE)) {
-                String roleName = parser.getAttributeValue(null, ATTRIBUTE_NAME);
-                ArraySet<String> roleHolders = parseRoleHoldersLocked(parser);
-                mRoles.put(roleName, roleHolders);
-            }
-        }
-    }
-
-    @NonNull
-    private ArraySet<String> parseRoleHoldersLocked(@NonNull XmlPullParser parser)
-            throws IOException, XmlPullParserException {
-        ArraySet<String> roleHolders = new ArraySet<>();
-
-        int type;
-        int depth;
-        int innerDepth = parser.getDepth() + 1;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
-            if (depth > innerDepth || type != XmlPullParser.START_TAG) {
-                continue;
-            }
-
-            if (parser.getName().equals(TAG_HOLDER)) {
-                String roleHolder = parser.getAttributeValue(null, ATTRIBUTE_NAME);
-                roleHolders.add(roleHolder);
-            }
-        }
-
-        return roleHolders;
     }
 
     /**
@@ -549,11 +461,6 @@
         }
     }
 
-    @NonNull
-    private static File getFile(@UserIdInt int userId) {
-        return new File(Environment.getUserSystemDirectory(userId), ROLES_FILE_NAME);
-    }
-
     /**
      * Callback for a user state.
      */
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 00ab973b..7523671 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -23,6 +23,7 @@
 import android.os.ParcelFileDescriptor;
 import android.view.InsetsState.InternalInsetsType;
 import android.view.WindowInsetsController.Appearance;
+import android.view.WindowInsetsController.Behavior;
 
 import com.android.internal.view.AppearanceRegion;
 import com.android.server.notification.NotificationDelegate;
@@ -84,7 +85,6 @@
 
     void startAssist(Bundle args);
     void onCameraLaunchGestureDetected(int source);
-    void topAppWindowChanged(int displayId, boolean isFullscreen, boolean isImmersive);
     void setDisableFlags(int displayId, int flags, String cause);
     void toggleSplitScreen();
     void appTransitionFinished(int displayId);
@@ -128,9 +128,10 @@
      */
     void onRecentsAnimationStateChanged(boolean running);
 
-    /** @see com.android.internal.statusbar.IStatusBar#onSystemBarAppearanceChanged */
-    void onSystemBarAppearanceChanged(int displayId, @Appearance int appearance,
-            AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme);
+    /** @see com.android.internal.statusbar.IStatusBar#onSystemBarAttributesChanged */
+    void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
+            AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
+            @Behavior int behavior, boolean isFullscreen);
 
     /** @see com.android.internal.statusbar.IStatusBar#showTransient */
     void showTransient(int displayId, @InternalInsetsType int[] types);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 3ee8dd7..6306c5c 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -57,6 +57,7 @@
 import android.util.SparseArray;
 import android.view.InsetsState.InternalInsetsType;
 import android.view.WindowInsetsController.Appearance;
+import android.view.WindowInsetsController.Behavior;
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
@@ -302,11 +303,6 @@
         }
 
         @Override
-        public void topAppWindowChanged(int displayId, boolean isFullscreen, boolean isImmersive) {
-            StatusBarManagerService.this.topAppWindowChanged(displayId, isFullscreen, isImmersive);
-        }
-
-        @Override
         public void setDisableFlags(int displayId, int flags, String cause) {
             StatusBarManagerService.this.setDisableFlags(displayId, flags, cause);
         }
@@ -521,16 +517,15 @@
         }
 
         @Override
-        public void onSystemBarAppearanceChanged(int displayId, @Appearance int appearance,
-                AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme) {
-            final UiState state = getUiState(displayId);
-            if (!state.appearanceEquals(appearance, appearanceRegions, navbarColorManagedByIme)) {
-                state.setAppearance(appearance, appearanceRegions, navbarColorManagedByIme);
-            }
+        public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
+                AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
+                @Behavior int behavior, boolean isFullscreen) {
+            getUiState(displayId).setBarAttributes(appearance, appearanceRegions,
+                    navbarColorManagedByIme, behavior, isFullscreen);
             if (mBar != null) {
                 try {
-                    mBar.onSystemBarAppearanceChanged(displayId, appearance, appearanceRegions,
-                            navbarColorManagedByIme);
+                    mBar.onSystemBarAttributesChanged(displayId, appearance, appearanceRegions,
+                            navbarColorManagedByIme, behavior, isFullscreen);
                 } catch (RemoteException ex) { }
             }
         }
@@ -981,27 +976,6 @@
         }
     }
 
-    /**
-     * Enables System UI to know whether the top app is fullscreen or not, and whether this app is
-     * in immersive mode or not.
-     */
-    private void topAppWindowChanged(int displayId, boolean isFullscreen, boolean isImmersive) {
-        enforceStatusBar();
-
-        synchronized(mLock) {
-            getUiState(displayId).setFullscreen(isFullscreen);
-            getUiState(displayId).setImmersive(isImmersive);
-            mHandler.post(() -> {
-                if (mBar != null) {
-                    try {
-                        mBar.topAppWindowChanged(displayId, isFullscreen, isImmersive);
-                    } catch (RemoteException ex) {
-                    }
-                }
-            });
-        }
-    }
-
     @Override
     public void setImeWindowStatus(int displayId, final IBinder token, final int vis,
             final int backDisposition, final boolean showImeSwitcher,
@@ -1068,8 +1042,8 @@
         private AppearanceRegion[] mAppearanceRegions = new AppearanceRegion[0];
         private ArraySet<Integer> mTransientBarTypes = new ArraySet<>();
         private boolean mNavbarColorManagedByIme = false;
+        private @Behavior int mBehavior;
         private boolean mFullscreen = false;
-        private boolean mImmersive = false;
         private int mDisabled1 = 0;
         private int mDisabled2 = 0;
         private int mImeWindowVis = 0;
@@ -1077,25 +1051,14 @@
         private boolean mShowImeSwitcher = false;
         private IBinder mImeToken = null;
 
-        private void setAppearance(@Appearance int appearance,
-                AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme) {
+        private void setBarAttributes(@Appearance int appearance,
+                AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
+                @Behavior int behavior, boolean isFullscreen) {
             mAppearance = appearance;
             mAppearanceRegions = appearanceRegions;
             mNavbarColorManagedByIme = navbarColorManagedByIme;
-        }
-
-        private boolean appearanceEquals(@Appearance int appearance,
-                AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme) {
-            if (mAppearance != appearance || mAppearanceRegions.length != appearanceRegions.length
-                    || mNavbarColorManagedByIme != navbarColorManagedByIme) {
-                return false;
-            }
-            for (int i = appearanceRegions.length - 1; i >= 0; i--) {
-                if (!mAppearanceRegions[i].equals(appearanceRegions[i])) {
-                    return false;
-                }
-            }
-            return true;
+            mBehavior = behavior;
+            mFullscreen = isFullscreen;
         }
 
         private void showTransient(@InternalInsetsType int[] types) {
@@ -1110,14 +1073,6 @@
             }
         }
 
-        private void setFullscreen(boolean isFullscreen) {
-            mFullscreen = isFullscreen;
-        }
-
-        private void setImmersive(boolean isImmersive) {
-            mImmersive = isImmersive;
-        }
-
         private int getDisabled1() {
             return mDisabled1;
         }
@@ -1200,7 +1155,7 @@
                     state.mAppearance, state.mAppearanceRegions, state.mImeWindowVis,
                     state.mImeBackDisposition, state.mShowImeSwitcher,
                     gatherDisableActionsLocked(mCurrentUserId, 2), state.mImeToken,
-                    state.mNavbarColorManagedByIme, state.mFullscreen, state.mImmersive,
+                    state.mNavbarColorManagedByIme, state.mBehavior, state.mFullscreen,
                     transientBarTypes);
         }
     }
diff --git a/services/core/java/com/android/server/storage/StorageSessionController.java b/services/core/java/com/android/server/storage/StorageSessionController.java
index 808d130..eb4a050 100644
--- a/services/core/java/com/android/server/storage/StorageSessionController.java
+++ b/services/core/java/com/android/server/storage/StorageSessionController.java
@@ -382,7 +382,11 @@
         }
     }
 
+    private static boolean isSupportedVolume(VolumeInfo vol) {
+        return isEmulatedOrPublic(vol) || vol.type == VolumeInfo.TYPE_STUB;
+    }
+
     private boolean shouldHandle(@Nullable VolumeInfo vol) {
-        return !mIsResetting && (vol == null || isEmulatedOrPublic(vol));
+        return !mIsResetting && (vol == null || isSupportedVolume(vol));
     }
 }
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index 93ba758..753b42b 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -192,7 +192,7 @@
                 request.getSystemTextClassifierMetadata(),
                 /* verifyCallingPackage= */ true,
                 /* attemptToBind= */ true,
-                service -> service.onSuggestSelection(sessionId, request, callback),
+                service -> service.onSuggestSelection(sessionId, request, wrap(callback)),
                 "onSuggestSelection",
                 callback);
     }
@@ -1057,6 +1057,8 @@
                 rewriteTextClassificationIcons(result);
             } else if (parcelled instanceof ConversationActions) {
                 rewriteConversationActionsIcons(result);
+            } else if (parcelled instanceof TextSelection) {
+                rewriteTextSelectionIcons(result);
             } else {
                 // do nothing.
             }
@@ -1067,10 +1069,32 @@
             }
         }
 
-        private static void rewriteTextClassificationIcons(Bundle result) {
-            final TextClassification classification = TextClassifierService.getResponse(result);
+        private static void rewriteTextSelectionIcons(Bundle result) {
+            final TextSelection textSelection = TextClassifierService.getResponse(result);
+            if (textSelection.getTextClassification() == null) {
+                return;
+            }
+            TextClassification newTextClassification =
+                    rewriteTextClassificationIcons(textSelection.getTextClassification());
+            if (newTextClassification == null) {
+                return;
+            }
+            TextClassifierService.putResponse(
+                    result,
+                    textSelection.toBuilder()
+                            .setTextClassification(newTextClassification)
+                            .build());
+        }
+
+        /**
+         * Returns a new {@link TextClassification} if any modification is made, {@code null}
+         * otherwise.
+         */
+        @Nullable
+        private static TextClassification rewriteTextClassificationIcons(
+                TextClassification textClassification) {
             boolean rewrite = false;
-            final List<RemoteAction> actions = classification.getActions();
+            final List<RemoteAction> actions = textClassification.getActions();
             final int size = actions.size();
             final List<RemoteAction> validActions = new ArrayList<>(size);
             for (int i = 0; i < size; i++) {
@@ -1084,13 +1108,21 @@
                 }
                 validActions.add(validAction);
             }
-            if (rewrite) {
-                TextClassifierService.putResponse(
-                        result,
-                        classification.toBuilder()
-                                .clearActions()
-                                .addActions(validActions)
-                                .build());
+            return rewrite
+                    ? textClassification
+                            .toBuilder()
+                            .clearActions()
+                            .addActions(validActions)
+                            .build()
+                    : null;
+        }
+
+        private static void rewriteTextClassificationIcons(Bundle result) {
+            final TextClassification classification = TextClassifierService.getResponse(result);
+            TextClassification newTextClassification = rewriteTextClassificationIcons(
+                    classification);
+            if (newTextClassification != null) {
+                TextClassifierService.putResponse(result, newTextClassification);
             }
         }
 
diff --git a/services/core/java/com/android/server/tv/TvInputHal.java b/services/core/java/com/android/server/tv/TvInputHal.java
index 42f12eb..0772503 100644
--- a/services/core/java/com/android/server/tv/TvInputHal.java
+++ b/services/core/java/com/android/server/tv/TvInputHal.java
@@ -51,7 +51,8 @@
     public interface Callback {
         void onDeviceAvailable(TvInputHardwareInfo info, TvStreamConfig[] configs);
         void onDeviceUnavailable(int deviceId);
-        void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs);
+        void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs,
+                int cableConnectionStatus);
         void onFirstFrameCaptured(int deviceId, int streamId);
     }
 
@@ -142,8 +143,9 @@
         mHandler.obtainMessage(EVENT_DEVICE_UNAVAILABLE, deviceId, 0).sendToTarget();
     }
 
-    private void streamConfigsChangedFromNative(int deviceId) {
-        mHandler.obtainMessage(EVENT_STREAM_CONFIGURATION_CHANGED, deviceId, 0).sendToTarget();
+    private void streamConfigsChangedFromNative(int deviceId, int cableConnectionStatus) {
+        mHandler.obtainMessage(EVENT_STREAM_CONFIGURATION_CHANGED, deviceId,
+            cableConnectionStatus).sendToTarget();
     }
 
     private void firstFrameCapturedFromNative(int deviceId, int streamId) {
@@ -184,6 +186,7 @@
             case EVENT_STREAM_CONFIGURATION_CHANGED: {
                 TvStreamConfig[] configs;
                 int deviceId = msg.arg1;
+                int cableConnectionStatus = msg.arg2;
                 synchronized (mLock) {
                     if (DEBUG) {
                         Slog.d(TAG, "EVENT_STREAM_CONFIGURATION_CHANGED: deviceId = " + deviceId);
@@ -191,7 +194,7 @@
                     retrieveStreamConfigsLocked(deviceId);
                     configs = mStreamConfigs.get(deviceId);
                 }
-                mCallback.onStreamConfigurationChanged(deviceId, configs);
+                mCallback.onStreamConfigurationChanged(deviceId, configs, cableConnectionStatus);
                 break;
             }
 
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index a036bd1..38ae51f 100755
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -156,6 +156,7 @@
         synchronized (mLock) {
             Connection connection = new Connection(info);
             connection.updateConfigsLocked(configs);
+            connection.updateCableConnectionStatusLocked(info.getCableConnectionStatus());
             mConnections.put(info.getDeviceId(), connection);
             buildHardwareListLocked();
             mHandler.obtainMessage(
@@ -202,7 +203,8 @@
     }
 
     @Override
-    public void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs) {
+    public void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs,
+            int cableConnectionStatus) {
         synchronized (mLock) {
             Connection connection = mConnections.get(deviceId);
             if (connection == null) {
@@ -211,12 +213,22 @@
                 return;
             }
             int previousConfigsLength = connection.getConfigsLengthLocked();
+            int previousCableConnectionStatus = connection.getInputStateLocked();
             connection.updateConfigsLocked(configs);
             String inputId = mHardwareInputIdMap.get(deviceId);
-            if (inputId != null
-                    && (previousConfigsLength == 0) != (connection.getConfigsLengthLocked() == 0)) {
-                mHandler.obtainMessage(ListenerHandler.STATE_CHANGED,
-                    connection.getInputStateLocked(), 0, inputId).sendToTarget();
+            if (inputId != null) {
+                if (connection.updateCableConnectionStatusLocked(cableConnectionStatus)) {
+                    if (previousCableConnectionStatus != connection.getInputStateLocked()) {
+                        mHandler.obtainMessage(ListenerHandler.STATE_CHANGED,
+                            connection.getInputStateLocked(), 0, inputId).sendToTarget();
+                    }
+                } else {
+                    if ((previousConfigsLength == 0)
+                            != (connection.getConfigsLengthLocked() == 0)) {
+                        mHandler.obtainMessage(ListenerHandler.STATE_CHANGED,
+                            connection.getInputStateLocked(), 0, inputId).sendToTarget();
+                    }
+                }
             }
             ITvInputHardwareCallback callback = connection.getCallbackLocked();
             if (callback != null) {
@@ -625,7 +637,7 @@
     }
 
     private class Connection implements IBinder.DeathRecipient {
-        private final TvInputHardwareInfo mHardwareInfo;
+        private TvInputHardwareInfo mHardwareInfo;
         private TvInputInfo mInfo;
         private TvInputHardwareImpl mHardware = null;
         private ITvInputHardwareCallback mCallback;
@@ -634,6 +646,7 @@
         private Integer mResolvedUserId = null;
         private Runnable mOnFirstFrameCaptured;
         private ResourceClientProfile mResourceClientProfile = null;
+        private boolean mIsCableConnectionStatusUpdated = false;
 
         public Connection(TvInputHardwareInfo hardwareInfo) {
             mHardwareInfo = hardwareInfo;
@@ -736,6 +749,17 @@
                     + " }";
         }
 
+        public boolean updateCableConnectionStatusLocked(int cableConnectionStatus) {
+            // Update connection status only if it's not default value
+            if (cableConnectionStatus != TvInputHardwareInfo.CABLE_CONNECTION_STATUS_UNKNOWN
+                    || mIsCableConnectionStatusUpdated) {
+                mIsCableConnectionStatusUpdated = true;
+                mHardwareInfo = mHardwareInfo.toBuilder()
+                    .cableConnectionStatus(cableConnectionStatus).build();
+            }
+            return mIsCableConnectionStatusUpdated;
+        }
+
         private int getConfigsLengthLocked() {
             return mConfigs == null ? 0 : mConfigs.length;
         }
@@ -743,7 +767,9 @@
         private int getInputStateLocked() {
             int configsLength = getConfigsLengthLocked();
             if (configsLength > 0) {
-                return INPUT_STATE_CONNECTED;
+                if (!mIsCableConnectionStatusUpdated) {
+                    return INPUT_STATE_CONNECTED;
+                }
             }
             switch (mHardwareInfo.getCableConnectionStatus()) {
                 case TvInputHardwareInfo.CABLE_CONNECTION_STATUS_CONNECTED:
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
index 072bdd2..988582d 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.media.IResourceManagerService;
 import android.media.tv.TvInputManager;
+import android.media.tv.tuner.TunerFrontendInfo;
 import android.media.tv.tunerresourcemanager.CasSessionRequest;
 import android.media.tv.tunerresourcemanager.IResourcesReclaimListener;
 import android.media.tv.tunerresourcemanager.ITunerResourceManager;
@@ -30,7 +31,6 @@
 import android.media.tv.tunerresourcemanager.TunerCiCamRequest;
 import android.media.tv.tunerresourcemanager.TunerDemuxRequest;
 import android.media.tv.tunerresourcemanager.TunerDescramblerRequest;
-import android.media.tv.tunerresourcemanager.TunerFrontendInfo;
 import android.media.tv.tunerresourcemanager.TunerFrontendRequest;
 import android.media.tv.tunerresourcemanager.TunerLnbRequest;
 import android.media.tv.tunerresourcemanager.TunerResourceManager;
@@ -578,7 +578,7 @@
             } else {
                 // Add a new fe resource
                 FrontendResource newFe = new FrontendResource.Builder(infos[i].handle)
-                                                 .type(infos[i].frontendType)
+                                                 .type(infos[i].type)
                                                  .exclusiveGroupId(infos[i].exclusiveGroupId)
                                                  .build();
                 addFrontendResource(newFe);
diff --git a/services/core/java/com/android/server/utils/quota/OWNERS b/services/core/java/com/android/server/utils/quota/OWNERS
new file mode 100644
index 0000000..a2943f3
--- /dev/null
+++ b/services/core/java/com/android/server/utils/quota/OWNERS
@@ -0,0 +1,4 @@
+dplotnikov@google.com
+kwekua@google.com
+omakoto@google.com
+yamasani@google.com
diff --git a/services/core/java/com/android/server/vibrator/InputDeviceDelegate.java b/services/core/java/com/android/server/vibrator/InputDeviceDelegate.java
index edbc058..3968723 100644
--- a/services/core/java/com/android/server/vibrator/InputDeviceDelegate.java
+++ b/services/core/java/com/android/server/vibrator/InputDeviceDelegate.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.hardware.input.InputManager;
+import android.os.CombinedVibrationEffect;
 import android.os.Handler;
 import android.os.VibrationAttributes;
 import android.os.VibrationEffect;
@@ -84,11 +85,21 @@
      *
      * @return {@link #isAvailable()}
      */
-    public boolean vibrateIfAvailable(int uid, String opPkg, VibrationEffect effect,
+    public boolean vibrateIfAvailable(int uid, String opPkg, CombinedVibrationEffect effect,
             String reason, VibrationAttributes attrs) {
         synchronized (mLock) {
-            for (int i = 0; i < mInputDeviceVibrators.size(); i++) {
-                mInputDeviceVibrators.valueAt(i).vibrate(uid, opPkg, effect, reason, attrs);
+            // TODO(b/159207608): Pass on the combined vibration once InputManager is merged
+            if (effect instanceof CombinedVibrationEffect.Mono) {
+                VibrationEffect e = ((CombinedVibrationEffect.Mono) effect).getEffect();
+                if (e instanceof VibrationEffect.Prebaked) {
+                    VibrationEffect fallback = ((VibrationEffect.Prebaked) e).getFallbackEffect();
+                    if (fallback != null) {
+                        e = fallback;
+                    }
+                }
+                for (int i = 0; i < mInputDeviceVibrators.size(); i++) {
+                    mInputDeviceVibrators.valueAt(i).vibrate(uid, opPkg, e, reason, attrs);
+                }
             }
             return mInputDeviceVibrators.size() > 0;
         }
diff --git a/services/core/java/com/android/server/vibrator/Vibration.java b/services/core/java/com/android/server/vibrator/Vibration.java
index b0266d0..fe3b03ab 100644
--- a/services/core/java/com/android/server/vibrator/Vibration.java
+++ b/services/core/java/com/android/server/vibrator/Vibration.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.os.CombinedVibrationEffect;
 import android.os.IBinder;
 import android.os.SystemClock;
 import android.os.VibrationAttributes;
@@ -72,14 +73,14 @@
 
     /** The actual effect to be played. */
     @Nullable
-    private VibrationEffect mEffect;
+    private CombinedVibrationEffect mEffect;
 
     /**
      * The original effect that was requested. Typically these two things differ because the effect
      * was scaled based on the users vibration intensity settings.
      */
     @Nullable
-    private VibrationEffect mOriginalEffect;
+    private CombinedVibrationEffect mOriginalEffect;
 
     /**
      * Start/end times in unix epoch time. Only to be used for debugging purposes and to correlate
@@ -90,7 +91,7 @@
     private long mEndTimeDebug;
     private Status mStatus;
 
-    public Vibration(IBinder token, int id, VibrationEffect effect,
+    public Vibration(IBinder token, int id, CombinedVibrationEffect effect,
             VibrationAttributes attrs, int uid, String opPkg, String reason) {
         this.token = token;
         this.mEffect = effect;
@@ -124,7 +125,7 @@
      * Replace this vibration effect if given {@code scaledEffect} is different, preserving the
      * original one for debug purposes.
      */
-    public void updateEffect(@NonNull VibrationEffect newEffect) {
+    public void updateEffect(@NonNull CombinedVibrationEffect newEffect) {
         if (newEffect.equals(mEffect)) {
             return;
         }
@@ -139,7 +140,7 @@
 
     /** Return the effect that should be played by this vibration. */
     @Nullable
-    public VibrationEffect getEffect() {
+    public CombinedVibrationEffect getEffect() {
         return mEffect;
     }
 
@@ -154,8 +155,8 @@
     public static final class DebugInfo {
         private final long mStartTimeDebug;
         private final long mEndTimeDebug;
-        private final VibrationEffect mEffect;
-        private final VibrationEffect mOriginalEffect;
+        private final CombinedVibrationEffect mEffect;
+        private final CombinedVibrationEffect mOriginalEffect;
         private final float mScale;
         private final VibrationAttributes mAttrs;
         private final int mUid;
@@ -163,8 +164,8 @@
         private final String mReason;
         private final Status mStatus;
 
-        public DebugInfo(long startTimeDebug, long endTimeDebug, VibrationEffect effect,
-                VibrationEffect originalEffect, float scale, VibrationAttributes attrs,
+        public DebugInfo(long startTimeDebug, long endTimeDebug, CombinedVibrationEffect effect,
+                CombinedVibrationEffect originalEffect, float scale, VibrationAttributes attrs,
                 int uid, String opPkg, String reason, Status status) {
             mStartTimeDebug = startTimeDebug;
             mEndTimeDebug = endTimeDebug;
@@ -228,7 +229,22 @@
             proto.end(token);
         }
 
-        private void dumpEffect(ProtoOutputStream proto, long fieldId, VibrationEffect effect) {
+        private void dumpEffect(
+                ProtoOutputStream proto, long fieldId, CombinedVibrationEffect combinedEffect) {
+            VibrationEffect effect;
+            // TODO(b/177805090): add proper support for dumping combined effects to proto
+            if (combinedEffect instanceof CombinedVibrationEffect.Mono) {
+                effect = ((CombinedVibrationEffect.Mono) combinedEffect).getEffect();
+            } else if (combinedEffect instanceof CombinedVibrationEffect.Stereo) {
+                effect = ((CombinedVibrationEffect.Stereo) combinedEffect).getEffects().valueAt(0);
+            } else if (combinedEffect instanceof CombinedVibrationEffect.Sequential) {
+                dumpEffect(proto, fieldId,
+                        ((CombinedVibrationEffect.Sequential) combinedEffect).getEffects().get(0));
+                return;
+            } else {
+                // Unknown combined effect, skip dump.
+                return;
+            }
             final long token = proto.start(fieldId);
             if (effect instanceof VibrationEffect.OneShot) {
                 dumpEffect(proto, VibrationEffectProto.ONESHOT, (VibrationEffect.OneShot) effect);
diff --git a/services/core/java/com/android/server/vibrator/VibrationScaler.java b/services/core/java/com/android/server/vibrator/VibrationScaler.java
index 5f7e47d..0fa4fe1 100644
--- a/services/core/java/com/android/server/vibrator/VibrationScaler.java
+++ b/services/core/java/com/android/server/vibrator/VibrationScaler.java
@@ -18,12 +18,16 @@
 
 import android.content.Context;
 import android.hardware.vibrator.V1_0.EffectStrength;
+import android.os.CombinedVibrationEffect;
 import android.os.IExternalVibratorService;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.util.Slog;
 import android.util.SparseArray;
 
+import java.util.List;
+import java.util.Objects;
+
 /** Controls vibration scaling. */
 // TODO(b/159207608): Make this package-private once vibrator services are moved to this package
 public final class VibrationScaler {
@@ -87,6 +91,43 @@
     }
 
     /**
+     * Scale a {@link CombinedVibrationEffect} based on the given usage hint for this vibration.
+     *
+     * @param combinedEffect the effect to be scaled
+     * @param usageHint      one of VibrationAttributes.USAGE_*
+     * @return The same given effect, if no changes were made, or a new
+     * {@link CombinedVibrationEffect} with resolved and scaled amplitude
+     */
+    public <T extends CombinedVibrationEffect> T scale(CombinedVibrationEffect combinedEffect,
+            int usageHint) {
+        if (combinedEffect instanceof CombinedVibrationEffect.Mono) {
+            VibrationEffect effect = ((CombinedVibrationEffect.Mono) combinedEffect).getEffect();
+            return (T) CombinedVibrationEffect.createSynced(scale(effect, usageHint));
+        } else if (combinedEffect instanceof CombinedVibrationEffect.Stereo) {
+            SparseArray<VibrationEffect> effects =
+                    ((CombinedVibrationEffect.Stereo) combinedEffect).getEffects();
+            CombinedVibrationEffect.SyncedCombination combination =
+                    CombinedVibrationEffect.startSynced();
+            for (int i = 0; i < effects.size(); i++) {
+                combination.addVibrator(effects.keyAt(i), scale(effects.valueAt(i), usageHint));
+            }
+            return (T) combination.combine();
+        } else if (combinedEffect instanceof CombinedVibrationEffect.Sequential) {
+            List<CombinedVibrationEffect> effects =
+                    ((CombinedVibrationEffect.Sequential) combinedEffect).getEffects();
+            CombinedVibrationEffect.SequentialCombination combination =
+                    CombinedVibrationEffect.startSequential();
+            for (CombinedVibrationEffect effect : effects) {
+                combination.addNext(scale(effect, usageHint));
+            }
+            return (T) combination.combine();
+        } else {
+            // Unknown combination, return same effect.
+            return (T) combinedEffect;
+        }
+    }
+
+    /**
      * Scale a {@link VibrationEffect} based on the given usage hint for this vibration.
      *
      * @param effect    the effect to be scaled
@@ -100,13 +141,23 @@
             int intensity = mSettingsController.getCurrentIntensity(usageHint);
             int newStrength = intensityToEffectStrength(intensity);
             VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) effect;
+            int strength = prebaked.getEffectStrength();
+            VibrationEffect fallback = prebaked.getFallbackEffect();
 
-            if (prebaked.getEffectStrength() == newStrength) {
+            if (fallback != null) {
+                VibrationEffect scaledFallback = scale(fallback, usageHint);
+                if (strength == newStrength && Objects.equals(fallback, scaledFallback)) {
+                    return (T) prebaked;
+                }
+
+                return (T) new VibrationEffect.Prebaked(prebaked.getId(), newStrength,
+                        scaledFallback);
+            } else if (strength == newStrength) {
                 return (T) prebaked;
+            } else {
+                return (T) new VibrationEffect.Prebaked(prebaked.getId(), prebaked.shouldFallback(),
+                        newStrength);
             }
-
-            return (T) new VibrationEffect.Prebaked(
-                    prebaked.getId(), prebaked.shouldFallback(), newStrength);
         }
 
         effect = effect.resolve(mDefaultVibrationAmplitude);
@@ -124,8 +175,6 @@
         return effect.scale(scale.factor);
     }
 
-
-
     /** Mapping of Vibrator.VIBRATION_INTENSITY_* values to {@link EffectStrength}. */
     private static int intensityToEffectStrength(int intensity) {
         switch (intensity) {
diff --git a/services/core/java/com/android/server/vibrator/VibrationThread.java b/services/core/java/com/android/server/vibrator/VibrationThread.java
new file mode 100644
index 0000000..a4d888b
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/VibrationThread.java
@@ -0,0 +1,791 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vibrator;
+
+import android.annotation.Nullable;
+import android.os.CombinedVibrationEffect;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.Trace;
+import android.os.VibrationEffect;
+import android.os.WorkSource;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.IBatteryStats;
+import com.android.internal.util.FrameworkStatsLog;
+
+import com.google.android.collect.Lists;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.PriorityQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/** Plays a {@link Vibration} in dedicated thread. */
+// TODO(b/159207608): Make this package-private once vibrator services are moved to this package
+public final class VibrationThread extends Thread implements IBinder.DeathRecipient {
+    private static final String TAG = "VibrationThread";
+    private static final boolean DEBUG = false;
+
+    /**
+     * Extra timeout added to the end of each synced vibration step as a timeout for the callback
+     * wait, to ensure it finishes even when callbacks from individual vibrators are lost.
+     */
+    private static final long CALLBACKS_EXTRA_TIMEOUT = 100;
+
+    /** Callbacks for playing a {@link Vibration}. */
+    public interface VibrationCallbacks {
+
+        /**
+         * Callback triggered before starting a synchronized vibration step. This will be called
+         * with {@code requiredCapabilities = 0} if no synchronization is required.
+         *
+         * @param requiredCapabilities The required syncing capabilities for this preparation step.
+         *                             Expects a combination of values from
+         *                             IVibratorManager.CAP_PREPARE_* and
+         *                             IVibratorManager.CAP_MIXED_TRIGGER_*.
+         * @param vibratorIds          The id of the vibrators to be prepared.
+         */
+        void prepareSyncedVibration(int requiredCapabilities, int[] vibratorIds);
+
+        /** Callback triggered after synchronized vibrations were prepared. */
+        void triggerSyncedVibration(long vibrationId);
+
+        /** Callback triggered when vibration thread is complete. */
+        void onVibrationEnded(long vibrationId, Vibration.Status status);
+    }
+
+    private final Object mLock = new Object();
+    private final WorkSource mWorkSource = new WorkSource();
+    private final PowerManager.WakeLock mWakeLock;
+    private final IBatteryStats mBatteryStatsService;
+    private final Vibration mVibration;
+    private final VibrationCallbacks mCallbacks;
+    private final SparseArray<VibratorController> mVibrators;
+
+    @GuardedBy("mLock")
+    @Nullable
+    private VibrateStep mCurrentVibrateStep;
+    @GuardedBy("this")
+    private boolean mForceStop;
+
+    // TODO(b/159207608): Remove this constructor once VibratorService is removed
+    public VibrationThread(Vibration vib, VibratorController vibrator,
+            PowerManager.WakeLock wakeLock, IBatteryStats batteryStatsService,
+            VibrationCallbacks callbacks) {
+        this(vib, toSparseArray(vibrator), wakeLock, batteryStatsService, callbacks);
+    }
+
+    public VibrationThread(Vibration vib, SparseArray<VibratorController> availableVibrators,
+            PowerManager.WakeLock wakeLock, IBatteryStats batteryStatsService,
+            VibrationCallbacks callbacks) {
+        mVibration = vib;
+        mCallbacks = callbacks;
+        mWakeLock = wakeLock;
+        mWorkSource.set(vib.uid);
+        mWakeLock.setWorkSource(mWorkSource);
+        mBatteryStatsService = batteryStatsService;
+
+        CombinedVibrationEffect effect = vib.getEffect();
+        mVibrators = new SparseArray<>();
+        for (int i = 0; i < availableVibrators.size(); i++) {
+            if (effect.hasVibrator(availableVibrators.keyAt(i))) {
+                mVibrators.put(availableVibrators.keyAt(i), availableVibrators.valueAt(i));
+            }
+        }
+    }
+
+    @Override
+    public void binderDied() {
+        cancel();
+    }
+
+    @Override
+    public void run() {
+        Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
+        mWakeLock.acquire();
+        try {
+            mVibration.token.linkToDeath(this, 0);
+            Vibration.Status status = playVibration();
+            mCallbacks.onVibrationEnded(mVibration.id, status);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Error linking vibration to token death", e);
+        } finally {
+            mVibration.token.unlinkToDeath(this, 0);
+            mWakeLock.release();
+        }
+    }
+
+    /** Cancel current vibration and shuts down the thread gracefully. */
+    public void cancel() {
+        synchronized (this) {
+            mForceStop = true;
+            notify();
+        }
+    }
+
+    /** Notify current vibration that a step has completed on given vibrator. */
+    public void vibratorComplete(int vibratorId) {
+        synchronized (mLock) {
+            if (mCurrentVibrateStep != null) {
+                mCurrentVibrateStep.vibratorComplete(vibratorId);
+            }
+        }
+    }
+
+    @VisibleForTesting
+    SparseArray<VibratorController> getVibrators() {
+        return mVibrators;
+    }
+
+    private Vibration.Status playVibration() {
+        Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "playVibration");
+        try {
+            List<Step> steps = generateSteps(mVibration.getEffect());
+            if (steps.isEmpty()) {
+                // No vibrator matching any incoming vibration effect.
+                return Vibration.Status.IGNORED;
+            }
+            Vibration.Status status = Vibration.Status.FINISHED;
+            final int stepCount = steps.size();
+            for (int i = 0; i < stepCount; i++) {
+                Step step = steps.get(i);
+                synchronized (mLock) {
+                    if (step instanceof VibrateStep) {
+                        mCurrentVibrateStep = (VibrateStep) step;
+                    } else {
+                        mCurrentVibrateStep = null;
+                    }
+                }
+                status = step.play();
+                if (status != Vibration.Status.FINISHED) {
+                    // This step was ignored by the vibrators, probably effects were unsupported.
+                    break;
+                }
+                if (mForceStop) {
+                    break;
+                }
+            }
+            if (mForceStop) {
+                return Vibration.Status.CANCELLED;
+            }
+            return status;
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+        }
+    }
+
+    private List<Step> generateSteps(CombinedVibrationEffect effect) {
+        if (effect instanceof CombinedVibrationEffect.Sequential) {
+            CombinedVibrationEffect.Sequential sequential =
+                    (CombinedVibrationEffect.Sequential) effect;
+            List<Step> steps = new ArrayList<>();
+            final int sequentialEffectCount = sequential.getEffects().size();
+            for (int i = 0; i < sequentialEffectCount; i++) {
+                int delay = sequential.getDelays().get(i);
+                if (delay > 0) {
+                    steps.add(new DelayStep(delay));
+                }
+                steps.addAll(generateSteps(sequential.getEffects().get(i)));
+            }
+            final int stepCount = steps.size();
+            for (int i = 0; i < stepCount; i++) {
+                if (steps.get(i) instanceof VibrateStep) {
+                    return steps;
+                }
+            }
+            // No valid vibrate step was generated, ignore effect completely.
+            return Lists.newArrayList();
+        }
+        VibrateStep vibrateStep = null;
+        if (effect instanceof CombinedVibrationEffect.Mono) {
+            vibrateStep = createVibrateStep(mapToAvailableVibrators(
+                    ((CombinedVibrationEffect.Mono) effect).getEffect()));
+        } else if (effect instanceof CombinedVibrationEffect.Stereo) {
+            vibrateStep = createVibrateStep(filterByAvailableVibrators(
+                    ((CombinedVibrationEffect.Stereo) effect).getEffects()));
+        }
+        return vibrateStep == null ? Lists.newArrayList() : Lists.newArrayList(vibrateStep);
+    }
+
+    @Nullable
+    private VibrateStep createVibrateStep(SparseArray<VibrationEffect> effects) {
+        if (effects.size() == 0) {
+            return null;
+        }
+        if (effects.size() == 1) {
+            // Create simplified step that handles a single vibrator.
+            return new SingleVibrateStep(mVibrators.get(effects.keyAt(0)), effects.valueAt(0));
+        }
+        return new SyncedVibrateStep(effects);
+    }
+
+    private SparseArray<VibrationEffect> mapToAvailableVibrators(VibrationEffect effect) {
+        SparseArray<VibrationEffect> mappedEffects = new SparseArray<>(mVibrators.size());
+        for (int i = 0; i < mVibrators.size(); i++) {
+            mappedEffects.put(mVibrators.keyAt(i), effect);
+        }
+        return mappedEffects;
+    }
+
+    private SparseArray<VibrationEffect> filterByAvailableVibrators(
+            SparseArray<VibrationEffect> effects) {
+        SparseArray<VibrationEffect> filteredEffects = new SparseArray<>();
+        for (int i = 0; i < effects.size(); i++) {
+            if (mVibrators.contains(effects.keyAt(i))) {
+                filteredEffects.put(effects.keyAt(i), effects.valueAt(i));
+            }
+        }
+        return filteredEffects;
+    }
+
+    private static SparseArray<VibratorController> toSparseArray(VibratorController controller) {
+        SparseArray<VibratorController> array = new SparseArray<>(1);
+        array.put(controller.getVibratorInfo().getId(), controller);
+        return array;
+    }
+
+    /**
+     * Get the duration the vibrator will be on for given {@code waveform}, starting at {@code
+     * startIndex} until the next time it's vibrating amplitude is zero.
+     */
+    private static long getVibratorOnDuration(VibrationEffect.Waveform waveform, int startIndex) {
+        long[] timings = waveform.getTimings();
+        int[] amplitudes = waveform.getAmplitudes();
+        int repeatIndex = waveform.getRepeatIndex();
+        int i = startIndex;
+        long timing = 0;
+        while (timings[i] == 0 || amplitudes[i] != 0) {
+            timing += timings[i++];
+            if (i >= timings.length) {
+                if (repeatIndex >= 0) {
+                    i = repeatIndex;
+                    // prevent infinite loop
+                    repeatIndex = -1;
+                } else {
+                    break;
+                }
+            }
+            if (i == startIndex) {
+                return 1000;
+            }
+        }
+        return timing;
+    }
+
+    /**
+     * Sleeps until given {@code wakeUpTime}.
+     *
+     * <p>This stops immediately when {@link #cancel()} is called.
+     */
+    private void waitUntil(long wakeUpTime) {
+        synchronized (this) {
+            long durationRemaining = wakeUpTime - SystemClock.uptimeMillis();
+            while (durationRemaining > 0) {
+                try {
+                    VibrationThread.this.wait(durationRemaining);
+                } catch (InterruptedException e) {
+                }
+                if (mForceStop) {
+                    break;
+                }
+                durationRemaining = wakeUpTime - SystemClock.uptimeMillis();
+            }
+        }
+    }
+
+    /**
+     * Sleeps until given {@link CountDownLatch} has finished or {@code wakeUpTime} was reached.
+     *
+     * <p>This stops immediately when {@link #cancel()} is called.
+     */
+    private void awaitUntil(CountDownLatch counter, long wakeUpTime) {
+        synchronized (this) {
+            long durationRemaining = wakeUpTime - SystemClock.uptimeMillis();
+            while (counter.getCount() > 0 && durationRemaining > 0) {
+                try {
+                    counter.await(durationRemaining, TimeUnit.MILLISECONDS);
+                } catch (InterruptedException e) {
+                }
+                if (mForceStop) {
+                    break;
+                }
+                durationRemaining = wakeUpTime - SystemClock.uptimeMillis();
+            }
+        }
+    }
+
+    private void noteVibratorOn(long duration) {
+        try {
+            mBatteryStatsService.noteVibratorOn(mVibration.uid, duration);
+            FrameworkStatsLog.write_non_chained(FrameworkStatsLog.VIBRATOR_STATE_CHANGED,
+                    mVibration.uid, null, FrameworkStatsLog.VIBRATOR_STATE_CHANGED__STATE__ON,
+                    duration);
+        } catch (RemoteException e) {
+        }
+    }
+
+    private void noteVibratorOff() {
+        try {
+            mBatteryStatsService.noteVibratorOff(mVibration.uid);
+            FrameworkStatsLog.write_non_chained(FrameworkStatsLog.VIBRATOR_STATE_CHANGED,
+                    mVibration.uid, null, FrameworkStatsLog.VIBRATOR_STATE_CHANGED__STATE__OFF,
+                    /* duration= */ 0);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /** Represent a single synchronized step while playing a {@link CombinedVibrationEffect}. */
+    private interface Step {
+        Vibration.Status play();
+    }
+
+    /** Represent a synchronized vibration step. */
+    private interface VibrateStep extends Step {
+        /** Callback to notify a vibrator has finished playing a effect. */
+        void vibratorComplete(int vibratorId);
+    }
+
+    /** Represent a vibration on a single vibrator. */
+    private final class SingleVibrateStep implements VibrateStep {
+        private final VibratorController mVibrator;
+        private final VibrationEffect mEffect;
+        private final CountDownLatch mCounter;
+
+        SingleVibrateStep(VibratorController vibrator, VibrationEffect effect) {
+            mVibrator = vibrator;
+            mEffect = effect;
+            mCounter = new CountDownLatch(1);
+        }
+
+        @Override
+        public void vibratorComplete(int vibratorId) {
+            if (mVibrator.getVibratorInfo().getId() != vibratorId) {
+                return;
+            }
+            if (mEffect instanceof VibrationEffect.OneShot
+                    || mEffect instanceof VibrationEffect.Waveform) {
+                // Oneshot and Waveform are controlled by amplitude steps, ignore callbacks.
+                return;
+            }
+            mVibrator.off();
+            mCounter.countDown();
+        }
+
+        @Override
+        public Vibration.Status play() {
+            Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "SingleVibrateStep");
+            long duration = -1;
+            try {
+                if (DEBUG) {
+                    Slog.d(TAG, "SingleVibrateStep starting...");
+                }
+                long startTime = SystemClock.uptimeMillis();
+                duration = vibratePredefined(mEffect);
+
+                if (duration > 0) {
+                    noteVibratorOn(duration);
+                    // Vibration is playing with no need to control amplitudes, just wait for native
+                    // callback or timeout.
+                    awaitUntil(mCounter, startTime + duration + CALLBACKS_EXTRA_TIMEOUT);
+                    return Vibration.Status.FINISHED;
+                }
+
+                startTime = SystemClock.uptimeMillis();
+                AmplitudeStep amplitudeStep = vibrateWithAmplitude(mEffect, startTime);
+                if (amplitudeStep == null) {
+                    // Vibration could not be played with or without amplitude steps.
+                    return Vibration.Status.IGNORED_UNSUPPORTED;
+                }
+
+                duration = mEffect instanceof VibrationEffect.Prebaked
+                        ? ((VibrationEffect.Prebaked) mEffect).getFallbackEffect().getDuration()
+                        : mEffect.getDuration();
+                if (duration < Long.MAX_VALUE) {
+                    // Only report vibration stats if we know how long we will be vibrating.
+                    noteVibratorOn(duration);
+                }
+                while (amplitudeStep != null) {
+                    waitUntil(amplitudeStep.startTime);
+                    if (mForceStop) {
+                        mVibrator.off();
+                        return Vibration.Status.CANCELLED;
+                    }
+                    amplitudeStep.play();
+                    amplitudeStep = amplitudeStep.nextStep();
+                }
+
+                return Vibration.Status.FINISHED;
+            } finally {
+                if (duration > 0 && duration < Long.MAX_VALUE) {
+                    noteVibratorOff();
+                }
+                if (DEBUG) {
+                    Slog.d(TAG, "SingleVibrateStep step done.");
+                }
+                Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+            }
+        }
+
+        /**
+         * Try to vibrate given effect using prebaked or composed predefined effects.
+         *
+         * @return the duration, in millis, expected for the vibration, or -1 if effect cannot be
+         * played with predefined effects.
+         */
+        private long vibratePredefined(VibrationEffect effect) {
+            if (effect instanceof VibrationEffect.Prebaked) {
+                VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) effect;
+                long duration = mVibrator.on(prebaked, mVibration.id);
+                if (duration > 0) {
+                    return duration;
+                }
+                if (prebaked.getFallbackEffect() != null) {
+                    return vibratePredefined(prebaked.getFallbackEffect());
+                }
+            } else if (effect instanceof VibrationEffect.Composed) {
+                VibrationEffect.Composed composed = (VibrationEffect.Composed) effect;
+                return mVibrator.on(composed, mVibration.id);
+            }
+            // OneShot and Waveform effects require amplitude change after calling vibrator.on.
+            return -1;
+        }
+
+        /**
+         * Try to vibrate given effect using {@link AmplitudeStep} to control vibration amplitude.
+         *
+         * @return the {@link AmplitudeStep} to start this vibration, or {@code null} if vibration
+         * do not require amplitude control.
+         */
+        private AmplitudeStep vibrateWithAmplitude(VibrationEffect effect, long startTime) {
+            int vibratorId = mVibrator.getVibratorInfo().getId();
+            if (effect instanceof VibrationEffect.OneShot) {
+                VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) effect;
+                return new AmplitudeStep(vibratorId, oneShot, startTime, startTime);
+            } else if (effect instanceof VibrationEffect.Waveform) {
+                VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) effect;
+                return new AmplitudeStep(vibratorId, waveform, startTime, startTime);
+            } else if (effect instanceof VibrationEffect.Prebaked) {
+                VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) effect;
+                if (prebaked.getFallbackEffect() != null) {
+                    return vibrateWithAmplitude(prebaked.getFallbackEffect(), startTime);
+                }
+            }
+            return null;
+        }
+    }
+
+    /** Represent a synchronized vibration step on multiple vibrators. */
+    private final class SyncedVibrateStep implements VibrateStep {
+        private final SparseArray<VibrationEffect> mEffects;
+        private final CountDownLatch mActiveVibratorCounter;
+
+        private final int mRequiredCapabilities;
+        private final int[] mVibratorIds;
+
+        SyncedVibrateStep(SparseArray<VibrationEffect> effects) {
+            mEffects = effects;
+            mActiveVibratorCounter = new CountDownLatch(mEffects.size());
+            // TODO(b/159207608): Calculate required capabilities for syncing this step.
+            mRequiredCapabilities = 0;
+            mVibratorIds = new int[effects.size()];
+            for (int i = 0; i < effects.size(); i++) {
+                mVibratorIds[i] = effects.keyAt(i);
+            }
+        }
+
+        @Override
+        public void vibratorComplete(int vibratorId) {
+            VibrationEffect effect = mEffects.get(vibratorId);
+            if (effect == null) {
+                return;
+            }
+            if (effect instanceof VibrationEffect.OneShot
+                    || effect instanceof VibrationEffect.Waveform) {
+                // Oneshot and Waveform are controlled by amplitude steps, ignore callbacks.
+                return;
+            }
+            mVibrators.get(vibratorId).off();
+            mActiveVibratorCounter.countDown();
+        }
+
+        @Override
+        public Vibration.Status play() {
+            Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "SyncedVibrateStep");
+            long timeout = -1;
+            try {
+                if (DEBUG) {
+                    Slog.d(TAG, "SyncedVibrateStep starting...");
+                }
+                final PriorityQueue<AmplitudeStep> nextSteps = new PriorityQueue<>(mEffects.size());
+                long startTime = SystemClock.uptimeMillis();
+                mCallbacks.prepareSyncedVibration(mRequiredCapabilities, mVibratorIds);
+                timeout = startVibrating(startTime, nextSteps);
+                mCallbacks.triggerSyncedVibration(mVibration.id);
+                noteVibratorOn(timeout);
+
+                while (!nextSteps.isEmpty()) {
+                    AmplitudeStep step = nextSteps.poll();
+                    waitUntil(step.startTime);
+                    if (mForceStop) {
+                        stopAllVibrators();
+                        return Vibration.Status.CANCELLED;
+                    }
+                    step.play();
+                    AmplitudeStep nextStep = step.nextStep();
+                    if (nextStep == null) {
+                        // This vibrator has finished playing the effect for this step.
+                        mActiveVibratorCounter.countDown();
+                    } else {
+                        nextSteps.add(nextStep);
+                    }
+                }
+
+                // All OneShot and Waveform effects have finished. Just wait for the other effects
+                // to end via native callbacks before finishing this synced step.
+                awaitUntil(mActiveVibratorCounter, startTime + timeout + CALLBACKS_EXTRA_TIMEOUT);
+                return Vibration.Status.FINISHED;
+            } finally {
+                if (timeout > 0) {
+                    noteVibratorOff();
+                }
+                if (DEBUG) {
+                    Slog.d(TAG, "SyncedVibrateStep done.");
+                }
+                Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+            }
+        }
+
+        /**
+         * Starts playing effects on designated vibrators.
+         *
+         * <p>This includes the {@link VibrationEffect.OneShot} and {@link VibrationEffect.Waveform}
+         * effects, that should start in sync with all other effects in this step. The waveforms are
+         * controlled by {@link AmplitudeStep} added to the {@code nextSteps} queue.
+         *
+         * @return A duration, in millis, to wait for the completion of all vibrations. This ignores
+         * any repeating waveform duration and returns the duration of a single run.
+         */
+        private long startVibrating(long startTime, PriorityQueue<AmplitudeStep> nextSteps) {
+            long maxDuration = 0;
+            for (int i = 0; i < mEffects.size(); i++) {
+                VibratorController controller = mVibrators.get(mEffects.keyAt(i));
+                VibrationEffect effect = mEffects.valueAt(i);
+                maxDuration = Math.max(maxDuration,
+                        startVibrating(controller, effect, startTime, nextSteps));
+            }
+            return maxDuration;
+        }
+
+        /**
+         * Play a single effect on a single vibrator.
+         *
+         * @return A duration, in millis, to wait for the completion of this effect. This ignores
+         * any repeating waveform duration and returns the duration of a single run to be used as
+         * timeout for callbacks.
+         */
+        private long startVibrating(VibratorController controller, VibrationEffect effect,
+                long startTime, PriorityQueue<AmplitudeStep> nextSteps) {
+            int vibratorId = controller.getVibratorInfo().getId();
+            long duration;
+            if (effect instanceof VibrationEffect.OneShot) {
+                VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) effect;
+                duration = oneShot.getDuration();
+                controller.on(duration, mVibration.id);
+                nextSteps.add(
+                        new AmplitudeStep(vibratorId, oneShot, startTime, startTime + duration));
+            } else if (effect instanceof VibrationEffect.Waveform) {
+                VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) effect;
+                duration = getVibratorOnDuration(waveform, 0);
+                if (duration > 0) {
+                    // Waveform starts by turning vibrator on. Do it in this sync vibrate step.
+                    controller.on(duration, mVibration.id);
+                }
+                nextSteps.add(
+                        new AmplitudeStep(vibratorId, waveform, startTime, startTime + duration));
+            } else if (effect instanceof VibrationEffect.Prebaked) {
+                VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) effect;
+                duration = controller.on(prebaked, mVibration.id);
+                if (duration <= 0 && prebaked.getFallbackEffect() != null) {
+                    return startVibrating(controller, prebaked.getFallbackEffect(), startTime,
+                            nextSteps);
+                }
+            } else if (effect instanceof VibrationEffect.Composed) {
+                VibrationEffect.Composed composed = (VibrationEffect.Composed) effect;
+                duration = controller.on(composed, mVibration.id);
+            } else {
+                duration = 0;
+            }
+            return duration;
+        }
+
+        private void stopAllVibrators() {
+            for (int vibratorId : mVibratorIds) {
+                VibratorController controller = mVibrators.get(vibratorId);
+                if (controller != null) {
+                    controller.off();
+                }
+            }
+        }
+    }
+
+    /** Represent a step to set amplitude on a single vibrator. */
+    private final class AmplitudeStep implements Step, Comparable<AmplitudeStep> {
+        public final int vibratorId;
+        public final VibrationEffect.Waveform waveform;
+        public final int currentIndex;
+        public final long startTime;
+        public final long vibratorStopTime;
+
+        AmplitudeStep(int vibratorId, VibrationEffect.OneShot oneShot,
+                long startTime, long vibratorStopTime) {
+            this(vibratorId, (VibrationEffect.Waveform) VibrationEffect.createWaveform(
+                    new long[]{oneShot.getDuration()},
+                    new int[]{oneShot.getAmplitude()}, /* repeat= */ -1),
+                    startTime,
+                    vibratorStopTime);
+        }
+
+        AmplitudeStep(int vibratorId, VibrationEffect.Waveform waveform,
+                long startTime, long vibratorStopTime) {
+            this(vibratorId, waveform, /* index= */ 0, startTime, vibratorStopTime);
+        }
+
+        AmplitudeStep(int vibratorId, VibrationEffect.Waveform waveform,
+                int index, long startTime, long vibratorStopTime) {
+            this.vibratorId = vibratorId;
+            this.waveform = waveform;
+            this.currentIndex = index;
+            this.startTime = startTime;
+            this.vibratorStopTime = vibratorStopTime;
+        }
+
+        @Override
+        public Vibration.Status play() {
+            Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "AmplitudeStep");
+            try {
+                if (DEBUG) {
+                    Slog.d(TAG, "AmplitudeStep starting on vibrator " + vibratorId + "...");
+                }
+                VibratorController controller = mVibrators.get(vibratorId);
+                if (currentIndex < 0) {
+                    controller.off();
+                    if (DEBUG) {
+                        Slog.d(TAG, "Vibrator turned off and finishing");
+                    }
+                    return Vibration.Status.FINISHED;
+                }
+                if (waveform.getTimings()[currentIndex] == 0) {
+                    // Skip waveform entries with zero timing.
+                    return Vibration.Status.FINISHED;
+                }
+                int amplitude = waveform.getAmplitudes()[currentIndex];
+                if (amplitude == 0) {
+                    controller.off();
+                    if (DEBUG) {
+                        Slog.d(TAG, "Vibrator turned off");
+                    }
+                    return Vibration.Status.FINISHED;
+                }
+                if (startTime >= vibratorStopTime) {
+                    // Vibrator has stopped. Turn vibrator back on for the duration of another
+                    // cycle before setting the amplitude.
+                    long onDuration = getVibratorOnDuration(waveform, currentIndex);
+                    if (onDuration > 0) {
+                        controller.on(onDuration, mVibration.id);
+                        if (DEBUG) {
+                            Slog.d(TAG, "Vibrator turned on for " + onDuration + "ms");
+                        }
+                    }
+                }
+                controller.setAmplitude(amplitude);
+                if (DEBUG) {
+                    Slog.d(TAG, "Amplitude changed to " + amplitude);
+                }
+                return Vibration.Status.FINISHED;
+            } finally {
+                if (DEBUG) {
+                    Slog.d(TAG, "AmplitudeStep done.");
+                }
+                Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+            }
+        }
+
+        @Override
+        public int compareTo(AmplitudeStep o) {
+            return Long.compare(startTime, o.startTime);
+        }
+
+        /** Return next {@link AmplitudeStep} from this waveform, of {@code null} if finished. */
+        @Nullable
+        public AmplitudeStep nextStep() {
+            if (currentIndex < 0) {
+                // Waveform has ended, no more steps to run.
+                return null;
+            }
+            long nextWakeUpTime = startTime + waveform.getTimings()[currentIndex];
+            int nextIndex = currentIndex + 1;
+            if (nextIndex >= waveform.getTimings().length) {
+                nextIndex = waveform.getRepeatIndex();
+            }
+            return new AmplitudeStep(vibratorId, waveform, nextIndex, nextWakeUpTime,
+                    nextVibratorStopTime());
+        }
+
+        /** Return next time the vibrator will stop after this step is played. */
+        private long nextVibratorStopTime() {
+            if (currentIndex < 0 || waveform.getTimings()[currentIndex] == 0
+                    || startTime < vibratorStopTime) {
+                return vibratorStopTime;
+            }
+            return startTime + getVibratorOnDuration(waveform, currentIndex);
+        }
+    }
+
+    /** Represent a delay step with fixed duration, that starts counting when it starts playing. */
+    private final class DelayStep implements Step {
+        private final int mDelay;
+
+        DelayStep(int delay) {
+            mDelay = delay;
+        }
+
+        @Override
+        public Vibration.Status play() {
+            Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "DelayStep");
+            try {
+                if (DEBUG) {
+                    Slog.d(TAG, "DelayStep of " + mDelay + "ms starting...");
+                }
+                waitUntil(SystemClock.uptimeMillis() + mDelay);
+                return Vibration.Status.FINISHED;
+            } finally {
+                if (DEBUG) {
+                    Slog.d(TAG, "DelayStep done.");
+                }
+                Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/vibrator/VibratorController.java b/services/core/java/com/android/server/vibrator/VibratorController.java
index 311c73b..53f52e2 100644
--- a/services/core/java/com/android/server/vibrator/VibratorController.java
+++ b/services/core/java/com/android/server/vibrator/VibratorController.java
@@ -142,6 +142,11 @@
         }
     }
 
+    @VisibleForTesting
+    public NativeWrapper getNativeWrapper() {
+        return mNativeWrapper;
+    }
+
     /** Return the {@link VibratorInfo} representing the vibrator controlled by this instance. */
     public VibratorInfo getVibratorInfo() {
         return mVibratorInfo;
@@ -240,6 +245,8 @@
      * {@link OnVibrationCompleteListener}.
      *
      * <p>This will affect the state of {@link #isVibrating()}.
+     *
+     * @return The duration of the effect playing, or 0 if unsupported.
      */
     public long on(VibrationEffect.Prebaked effect, long vibrationId) {
         synchronized (mLock) {
@@ -257,15 +264,20 @@
      * {@link OnVibrationCompleteListener}.
      *
      * <p>This will affect the state of {@link #isVibrating()}.
+     *
+     * @return The duration of the effect playing, or 0 if unsupported.
      */
-    public void on(VibrationEffect.Composed effect, long vibrationId) {
+    public long on(VibrationEffect.Composed effect, long vibrationId) {
         if (!mVibratorInfo.hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
-            return;
+            return 0;
         }
         synchronized (mLock) {
             mNativeWrapper.compose(effect.getPrimitiveEffects().toArray(
                     new VibrationEffect.Composition.PrimitiveEffect[0]), vibrationId);
             notifyVibratorOnLocked();
+            // Compose don't actually give us an estimated duration, so we just guess here.
+            // TODO(b/177807015): use exposed durations from IVibrator here instead
+            return 20 * effect.getPrimitiveEffects().size();
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 9554f2e..f9cc334 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -294,6 +294,7 @@
 import android.view.WindowManager.LayoutParams;
 import android.view.WindowManager.TransitionOldType;
 import android.view.animation.Animation;
+import android.window.IRemoteTransition;
 import android.window.TaskSnapshot;
 import android.window.WindowContainerToken;
 
@@ -467,6 +468,7 @@
     private ActivityOptions mPendingOptions;
     /** Non-null if {@link #mPendingOptions} specifies the remote animation. */
     private RemoteAnimationAdapter mPendingRemoteAnimation;
+    private IRemoteTransition mPendingRemoteTransition;
     ActivityOptions returningOptions; // options that are coming back via convertToTranslucent
     AppTimeTracker appTimeTracker; // set if we are tracking the time in this app/task/activity
     ActivityServiceConnectionsHolder mServiceConnectionsHolder; // Service connections.
@@ -894,6 +896,9 @@
             pw.print("pendingRemoteAnimationCallingPid=");
             pw.println(mPendingRemoteAnimation.getCallingPid());
         }
+        if (mPendingRemoteTransition != null) {
+            pw.print(prefix + " pendingRemoteTransition=" + mPendingRemoteTransition);
+        }
         if (appTimeTracker != null) {
             appTimeTracker.dumpWithHeader(pw, prefix, false);
         }
@@ -3244,6 +3249,11 @@
 
     @Override
     void removeImmediately() {
+        if (!finishing) {
+            // If Task#removeImmediately is called directly with alive activities, ensure that the
+            // activities are destroyed and detached from process.
+            destroyImmediately("removeImmediately");
+        }
         onRemovedFromDisplay();
         super.removeImmediately();
     }
@@ -3884,6 +3894,7 @@
         if (options.getAnimationType() == ANIM_REMOTE_ANIMATION) {
             mPendingRemoteAnimation = options.getRemoteAnimationAdapter();
         }
+        mPendingRemoteTransition = options.getRemoteTransition();
     }
 
     void applyOptionsAnimation() {
@@ -4064,6 +4075,7 @@
     void clearOptionsAnimation() {
         mPendingOptions = null;
         mPendingRemoteAnimation = null;
+        mPendingRemoteTransition = null;
     }
 
     ActivityOptions getOptions() {
@@ -4078,6 +4090,12 @@
         return opts;
     }
 
+    IRemoteTransition takeRemoteTransition() {
+        IRemoteTransition out = mPendingRemoteTransition;
+        mPendingRemoteTransition = null;
+        return out;
+    }
+
     boolean allowMoveToFront() {
         return mPendingOptions == null || !mPendingOptions.getAvoidMoveToFront();
     }
@@ -4773,7 +4791,7 @@
 
     void makeVisibleIfNeeded(ActivityRecord starting, boolean reportToClient) {
         // This activity is not currently visible, but is running. Tell it to become visible.
-        if (mState == RESUMED || this == starting) {
+        if ((mState == RESUMED && mVisibleRequested) || this == starting) {
             if (DEBUG_VISIBILITY) Slog.d(TAG_VISIBILITY,
                     "Not making visible, r=" + this + " state=" + mState + " starting=" + starting);
             return;
@@ -6479,8 +6497,9 @@
         mLastReportedConfiguration.setConfiguration(global, override);
     }
 
-    boolean hasCompatDisplayInsets() {
-        return mCompatDisplayInsets != null;
+    @Nullable
+    CompatDisplayInsets getCompatDisplayInsets() {
+        return mCompatDisplayInsets;
     }
 
     /**
@@ -7803,13 +7822,16 @@
     /**
      * The precomputed insets of the display in each rotation. This is used to make the size
      * compatibility mode activity compute the configuration without relying on its current display.
-     * This currently only supports fullscreen and freeform windowing mode.
      */
     static class CompatDisplayInsets {
+        /** The container width on rotation 0. */
         private final int mWidth;
+        /** The container height on rotation 0. */
         private final int mHeight;
+        /** Whether the {@link Task} windowingMode represents a floating window*/
         final boolean mIsFloating;
-
+        /** Whether the {@link Task} is letterboxed when the unresizable activity is first shown. */
+        final boolean mIsTaskLetterboxed;
         /**
          * The nonDecorInsets for each rotation. Includes the navigation bar and cutout insets. It
          * is used to compute the appBounds.
@@ -7836,27 +7858,24 @@
                     mNonDecorInsets[rotation] = emptyRect;
                     mStableInsets[rotation] = emptyRect;
                 }
+                mIsTaskLetterboxed = false;
                 return;
             }
 
             final Task task = container.getTask();
-            if (task != null && task.isTaskLetterboxed()) {
-                // For apps in Task letterbox, it should fill the task bounds.
-                final Point dimensions = getRotationZeroDimensions(task);
-                mWidth = dimensions.x;
-                mHeight = dimensions.y;
-            } else {
-                // If the activity is not floating nor letterboxed, assume it fills the root.
-                final RootDisplayArea root = container.getRootDisplayArea();
-                if (root == null || root == display) {
-                    mWidth = display.mBaseDisplayWidth;
-                    mHeight = display.mBaseDisplayHeight;
-                } else {
-                    final Point dimensions = getRotationZeroDimensions(root);
-                    mWidth = dimensions.x;
-                    mHeight = dimensions.y;
-                }
-            }
+            mIsTaskLetterboxed = task != null && task.isTaskLetterboxed();
+
+            // Store the bounds of the Task for the non-resizable activity to use in size compat
+            // mode so that the activity will not be resized regardless the windowing mode it is
+            // currently in.
+            final WindowContainer filledContainer = task != null ? task : display;
+            final Point dimensions = getRotationZeroDimensions(filledContainer);
+            mWidth = dimensions.x;
+            mHeight = dimensions.y;
+
+            // Bounds of the filled container if it doesn't fill the display.
+            final Rect unfilledContainerBounds =
+                    filledContainer.getBounds().equals(display.getBounds()) ? null : new Rect();
             final DisplayPolicy policy = display.getDisplayPolicy();
             for (int rotation = 0; rotation < 4; rotation++) {
                 mNonDecorInsets[rotation] = new Rect();
@@ -7869,6 +7888,20 @@
                 policy.getNonDecorInsetsLw(rotation, dw, dh, cutout, mNonDecorInsets[rotation]);
                 mStableInsets[rotation].set(mNonDecorInsets[rotation]);
                 policy.convertNonDecorInsetsToStableInsets(mStableInsets[rotation], rotation);
+
+                if (unfilledContainerBounds == null) {
+                    continue;
+                }
+                // The insets is based on the display, but the container may be smaller than the
+                // display, so update the insets to exclude parts that are not intersected with the
+                // container.
+                unfilledContainerBounds.set(filledContainer.getBounds());
+                display.rotateBounds(
+                        filledContainer.getConfiguration().windowConfiguration.getRotation(),
+                        rotation,
+                        unfilledContainerBounds);
+                updateInsetsForBounds(unfilledContainerBounds, dw, dh, mNonDecorInsets[rotation]);
+                updateInsetsForBounds(unfilledContainerBounds, dw, dh, mStableInsets[rotation]);
             }
         }
 
@@ -7886,6 +7919,18 @@
             return rotated ? new Point(height, width) : new Point(width, height);
         }
 
+        /**
+         * Updates the display insets to exclude the parts that are not intersected with the given
+         * bounds.
+         */
+        private static void updateInsetsForBounds(Rect bounds, int displayWidth, int displayHeight,
+                Rect inset) {
+            inset.left = Math.max(0, inset.left - bounds.left);
+            inset.top = Math.max(0, inset.top - bounds.top);
+            inset.right = Math.max(0, bounds.right - displayWidth + inset.right);
+            inset.bottom = Math.max(0, bounds.bottom - displayHeight + inset.bottom);
+        }
+
         void getBoundsByRotation(Rect outBounds, int rotation) {
             final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
             final int dw = rotated ? mHeight : mWidth;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 20625c8..e67210e 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -110,6 +110,7 @@
 import android.util.DebugUtils;
 import android.util.Pools.SynchronizedPool;
 import android.util.Slog;
+import android.window.IRemoteTransition;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.HeavyWeightSwitcherActivity;
@@ -1573,6 +1574,10 @@
         final Transition newTransition = (!mService.getTransitionController().isCollecting()
                 && mService.getTransitionController().getTransitionPlayer() != null)
                 ? mService.getTransitionController().createTransition(TRANSIT_OPEN) : null;
+        IRemoteTransition remoteTransition = r.takeRemoteTransition();
+        if (newTransition != null && remoteTransition != null) {
+            newTransition.setRemoteTransition(remoteTransition);
+        }
         mService.getTransitionController().collect(r);
         try {
             mService.deferWindowLayout();
@@ -1611,7 +1616,7 @@
                 }
                 if (newTransition != null) {
                     mService.getTransitionController().requestStartTransition(newTransition,
-                            r.getTask());
+                            mTargetTask, remoteTransition);
                 } else {
                     // Make the collecting transition wait until this request is ready.
                     mService.getTransitionController().setReady(false);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 3c06488..b332739 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -2674,8 +2674,8 @@
                         .setWindowingMode(rootTask.getWindowingMode())
                         .setActivityType(rootTask.getActivityType())
                         .setActivityInfo(ainfo)
-                        .setParent(rootTask.getDisplayArea())
                         .setIntent(intent)
+                        .setTaskId(rootTask.getDisplayArea().getNextRootTaskId())
                         .build();
 
                 if (!mRecentTasks.addToBottom(task)) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 599bf37..a68f5575 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -1365,7 +1365,8 @@
             mUserLeaving = true;
         }
 
-        mService.getTransitionController().requestTransitionIfNeeded(TRANSIT_TO_FRONT, task);
+        mService.getTransitionController().requestTransitionIfNeeded(TRANSIT_TO_FRONT,
+                0 /* flags */, task, options != null ? options.getRemoteTransition() : null);
         reason = reason + " findTaskToMoveToFront";
         boolean reparented = false;
         if (task.isResizeable() && canUseActivityOptionsLaunchBounds(options)) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index d4629d9..9769244 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -664,8 +664,9 @@
     // Used in updating override configurations
     private final Configuration mTempConfig = new Configuration();
 
-    // Used in performing layout
-    private boolean mTmpWindowsBehindIme;
+    // Used in performing layout, to record the insets provided by other windows above the current
+    // window.
+    private InsetsState mTmpAboveInsetsState = new InsetsState();
 
     /**
      * Used to prevent recursions when calling
@@ -765,17 +766,11 @@
                     + " parentHidden=" + w.isParentWindowHidden());
         }
 
-        // Sets mBehindIme for each window. Windows behind IME can get IME insets.
-        if (w.mBehindIme != mTmpWindowsBehindIme) {
-            w.mBehindIme = mTmpWindowsBehindIme;
-            if (getInsetsStateController().getRawInsetsState().getSourceOrDefaultVisibility(
-                    ITYPE_IME)) {
-                // If IME is invisible, behind IME or not doesn't make the insets different.
-                mWinInsetsChanged.add(w);
-            }
-        }
-        if (w == mInputMethodWindow) {
-            mTmpWindowsBehindIme = true;
+        // Sets mAboveInsets for each window. Windows behind the window providing the insets can
+        // receive the insets.
+        if (!w.mAboveInsetsState.equals(mTmpAboveInsetsState)) {
+            w.mAboveInsetsState.set(mTmpAboveInsetsState);
+            mWinInsetsChanged.add(w);
         }
 
         // If this view is GONE, then skip it -- keep the current frame, and let the caller know
@@ -811,8 +806,16 @@
                     + " mContainingFrame=" + w.getContainingFrame()
                     + " mDisplayFrame=" + w.getDisplayFrame());
         }
+        provideInsetsByWindow(w);
     };
 
+    private void provideInsetsByWindow(WindowState w) {
+        for (int i = 0; i < w.mProvidedInsetsSources.size(); i++) {
+            final InsetsSource providedSource = w.mProvidedInsetsSources.valueAt(i);
+            mTmpAboveInsetsState.addSource(providedSource);
+        }
+    }
+
     private final Consumer<WindowState> mPerformLayoutAttached = w -> {
         if (w.mLayoutAttached) {
             if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + w + " mHaveFrame=" + w.mHaveFrame
@@ -3643,7 +3646,10 @@
                 && mImeLayeringTarget.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
                 // An activity with override bounds should be letterboxed inside its parent bounds,
                 // so it doesn't fill the screen.
-                && mImeLayeringTarget.mActivityRecord.matchParentBounds();
+                && mImeLayeringTarget.mActivityRecord.matchParentBounds()
+                // IME is attached to non-Letterboxed app windows, other than windows with
+                // LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER flag. (Refer to WS.isLetterboxedAppWindow())
+                && mImeLayeringTarget.matchesRootDisplayAreaBounds();
     }
 
     /**
@@ -4191,6 +4197,14 @@
                 calculateDisplayCutoutForRotation(mDisplayInfo.rotation));
         mDisplayPolicy.beginLayoutLw(mDisplayFrames, getConfiguration().uiMode);
 
+        // Used to indicate that we have processed the insets windows. This needs to be after
+        // beginLayoutLw to ensure the raw insets state display related info is initialized.
+        final InsetsState rawInsetsState = getInsetsStateController().getRawInsetsState();
+        mTmpAboveInsetsState = new InsetsState();
+        mTmpAboveInsetsState.setDisplayFrame(rawInsetsState.getDisplayFrame());
+        mTmpAboveInsetsState.setDisplayCutout(rawInsetsState.getDisplayCutout());
+        mTmpAboveInsetsState.mirrorAlwaysVisibleInsetsSources(rawInsetsState);
+
         int seq = mLayoutSeq + 1;
         if (seq < 0) seq = 0;
         mLayoutSeq = seq;
@@ -4200,8 +4214,6 @@
         mTmpWindow = null;
         mTmpInitial = initial;
 
-        // Used to indicate that we have processed the IME window.
-        mTmpWindowsBehindIme = false;
 
         // First perform layout of any root windows (not attached to another window).
         forAllWindows(mPerformLayout, true /* traverseTopToBottom */);
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index fb005b3..d9bc619 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -42,10 +42,6 @@
 import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
 import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS;
 import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS;
-import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE;
-import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_TOUCH;
-import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
-import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
@@ -121,7 +117,6 @@
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.Region;
-import android.hardware.input.InputManager;
 import android.hardware.power.Boost;
 import android.os.Handler;
 import android.os.IBinder;
@@ -136,16 +131,10 @@
 import android.util.SparseArray;
 import android.view.DisplayCutout;
 import android.view.Gravity;
-import android.view.InputChannel;
-import android.view.InputDevice;
-import android.view.InputEvent;
-import android.view.InputEventReceiver;
 import android.view.InsetsFlags;
 import android.view.InsetsSource;
 import android.view.InsetsState;
 import android.view.InsetsState.InternalInsetsType;
-import android.view.MotionEvent;
-import android.view.PointerIcon;
 import android.view.Surface;
 import android.view.View;
 import android.view.ViewDebug;
@@ -334,7 +323,6 @@
 
     // What we last reported to system UI about whether the focused window is fullscreen/immersive.
     private boolean mLastFocusIsFullscreen = false;
-    private boolean mLastFocusIsImmersive = false;
 
     // If nonzero, a panic gesture was performed at that time in uptime millis and is still pending.
     private long mPendingPanicGestureUptime;
@@ -363,9 +351,6 @@
     private boolean mDreamingLockscreen;
     private boolean mAllowLockscreenWhenOn;
 
-    @VisibleForTesting
-    EventReceiverInputConsumer mInputConsumer;
-
     private PointerLocationView mPointerLocationView;
 
     /**
@@ -380,6 +365,14 @@
 
     private RefreshRatePolicy mRefreshRatePolicy;
 
+    /**
+     * If true, attach the navigation bar to the current transition app.
+     * The value is read from config_attachNavBarToAppDuringTransition and could be overlaid by RRO
+     * when the navigation bar mode is changed.
+     */
+    private boolean mShouldAttachNavBarToAppDuringTransition;
+    private NavBarFadeAnimationController mNavBarFadeAnimationController;
+
     // -------- PolicyHandler --------
     private static final int MSG_REQUEST_TRANSIENT_BARS = 2;
     private static final int MSG_DISPOSE_INPUT_CONSUMER = 3;
@@ -1086,6 +1079,7 @@
                 break;
             case TYPE_NAVIGATION_BAR:
                 mNavigationBar = win;
+                updateNavBarFadeController();
                 mDisplayContent.setInsetProvider(ITYPE_NAVIGATION_BAR, win,
                         (displayFrames, windowState, inOutFrame) -> {
 
@@ -1231,6 +1225,7 @@
             mDisplayContent.setInsetProvider(ITYPE_STATUS_BAR, null, null);
         } else if (mNavigationBar == win || mNavigationBarAlt == win) {
             mNavigationBar = null;
+            updateNavBarFadeController();
             mNavigationBarAlt = null;
             mDisplayContent.setInsetProvider(ITYPE_NAVIGATION_BAR, null, null);
         } else if (mNotificationShade == win) {
@@ -1437,49 +1432,6 @@
         return mForceShowSystemBars;
     }
 
-    /**
-     * Input handler used while nav bar is hidden.  Captures any touch on the screen,
-     * to determine when the nav bar should be shown and prevent applications from
-     * receiving those touches.
-     */
-    private final class HideNavInputEventReceiver extends InputEventReceiver {
-        HideNavInputEventReceiver(InputChannel inputChannel, Looper looper) {
-            super(inputChannel, looper);
-        }
-
-        @Override
-        public void onInputEvent(InputEvent event) {
-            try {
-                if (event instanceof MotionEvent
-                        && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
-                    final MotionEvent motionEvent = (MotionEvent) event;
-                    if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
-                        // When the user taps down, we re-show the nav bar.
-                        boolean changed = false;
-                        synchronized (mLock) {
-                            if (mInputConsumer == null) {
-                                return;
-                            }
-                            showSystemBars();
-                        }
-                    }
-                }
-            } finally {
-                finishInputEvent(event, false /* handled */);
-            }
-        }
-
-        private void showSystemBars() {
-            final InsetsSourceProvider provider = mDisplayContent.getInsetsStateController()
-                    .peekSourceProvider(ITYPE_NAVIGATION_BAR);
-            final InsetsControlTarget target =
-                    provider != null ? provider.getControlTarget() : null;
-            if (target != null) {
-                target.showInsets(Type.systemBars(), false /* fromIme */);
-            }
-        }
-    }
-
     private void simulateLayoutDecorWindow(WindowState win, DisplayFrames displayFrames,
             InsetsState insetsState, WindowFrames simulatedWindowFrames,
             SparseArray<Rect> contentFrames, Consumer<Rect> layout) {
@@ -1529,48 +1481,10 @@
         displayFrames.onBeginLayout(mDisplayContent.getInsetsStateController().getRawInsetsState());
         mSystemGestures.screenWidth = displayFrames.mUnrestricted.width();
         mSystemGestures.screenHeight = displayFrames.mUnrestricted.height();
-
-        updateHideNavInputEventReceiver();
-
         layoutNavigationBar(displayFrames, uiMode, null /* simulatedContentFrame */);
         layoutStatusBar(displayFrames, null /* simulatedContentFrame */);
     }
 
-    void updateHideNavInputEventReceiver() {
-        final InsetsSourceProvider provider = mDisplayContent.getInsetsStateController()
-                .peekSourceProvider(ITYPE_NAVIGATION_BAR);
-        final InsetsControlTarget navControlTarget =
-                provider != null ? provider.getControlTarget() : null;
-        final WindowState navControllingWin =
-                navControlTarget instanceof WindowState ? (WindowState) navControlTarget : null;
-        final boolean navVisible = navControllingWin != null
-                ? navControllingWin.getRequestedVisibility(ITYPE_NAVIGATION_BAR)
-                : InsetsState.getDefaultVisibility(ITYPE_NAVIGATION_BAR);
-        final boolean showBarsByTouch = navControllingWin != null
-                && navControllingWin.mAttrs.insetsFlags.behavior == BEHAVIOR_SHOW_BARS_BY_TOUCH;
-        // When the navigation bar isn't visible, we put up a fake input window to catch all
-        // touch events. This way we can detect when the user presses anywhere to bring back the
-        // nav bar and ensure the application doesn't see the event.
-        if (navVisible || !showBarsByTouch) {
-            if (mInputConsumer != null) {
-                mInputConsumer.dismiss();
-                mHandler.sendMessage(
-                        mHandler.obtainMessage(MSG_DISPOSE_INPUT_CONSUMER, mInputConsumer));
-                mInputConsumer = null;
-                Slog.v(TAG, INPUT_CONSUMER_NAVIGATION + " dismissed.");
-            }
-        } else if (mInputConsumer == null && getStatusBar() != null && canHideNavigationBar()) {
-            mInputConsumer = mDisplayContent.getInputMonitor().createInputConsumer(
-                    mHandler.getLooper(),
-                    INPUT_CONSUMER_NAVIGATION,
-                    HideNavInputEventReceiver::new);
-            Slog.v(TAG, INPUT_CONSUMER_NAVIGATION + " created.");
-            // As long as mInputConsumer is active, hover events are not dispatched to the app
-            // and the pointer icon is likely to become stale. Hide it to avoid confusion.
-            InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_NULL);
-        }
-    }
-
     private void layoutStatusBar(DisplayFrames displayFrames, Rect simulatedContentFrame) {
         // decide where the status bar goes ahead of time
         if (mStatusBar == null) {
@@ -2195,6 +2109,13 @@
                         - getNavigationBarFrameHeight(portraitRotation, uiMode);
 
         updateConfigurationAndScreenSizeDependentBehaviors();
+
+        final boolean shouldAttach =
+                res.getBoolean(R.bool.config_attachNavBarToAppDuringTransition);
+        if (mShouldAttachNavBarToAppDuringTransition != shouldAttach) {
+            mShouldAttachNavBarToAppDuringTransition = shouldAttach;
+            updateNavBarFadeController();
+        }
     }
 
     void updateConfigurationAndScreenSizeDependentBehaviors() {
@@ -2645,8 +2566,6 @@
                 mTopFullscreenOpaqueOrDimmingWindowState,
                 mDisplayContent.mInputMethodWindow, navColorWin) | opaqueAppearance;
         final int behavior = win.mAttrs.insetsFlags.behavior;
-        final boolean isImmersive = behavior == BEHAVIOR_SHOW_BARS_BY_SWIPE
-                || behavior == BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
         final boolean isFullscreen = !win.getRequestedVisibility(ITYPE_STATUS_BAR)
                 || !win.getRequestedVisibility(ITYPE_NAVIGATION_BAR);
         if (mLastDisableFlags == disableFlags
@@ -2655,7 +2574,6 @@
                 && mLastDockedAppearance == dockedAppearance
                 && mLastBehavior == behavior
                 && mLastFocusIsFullscreen == isFullscreen
-                && mLastFocusIsImmersive == isImmersive
                 && mLastNonDockedStackBounds.equals(mNonDockedStackBounds)
                 && mLastDockedStackBounds.equals(mDockedStackBounds)) {
             return false;
@@ -2671,7 +2589,6 @@
         mLastDockedAppearance = dockedAppearance;
         mLastBehavior = behavior;
         mLastFocusIsFullscreen = isFullscreen;
-        mLastFocusIsImmersive = isImmersive;
         mLastNonDockedStackBounds.set(mNonDockedStackBounds);
         mLastDockedStackBounds.set(mDockedStackBounds);
         final Rect fullscreenStackBounds = new Rect(mNonDockedStackBounds);
@@ -2688,9 +2605,8 @@
             if (statusBar != null) {
                 final int displayId = getDisplayId();
                 statusBar.setDisableFlags(displayId, disableFlags, cause);
-                statusBar.onSystemBarAppearanceChanged(displayId, appearance,
-                        appearanceRegions, isNavbarColorManagedByIme);
-                statusBar.topAppWindowChanged(displayId, isFullscreen, isImmersive);
+                statusBar.onSystemBarAttributesChanged(displayId, appearance, appearanceRegions,
+                        isNavbarColorManagedByIme, behavior, isFullscreen);
 
             }
         });
@@ -2922,11 +2838,8 @@
         if (win == null) {
             return false;
         }
-        final int behavior = win.mAttrs.insetsFlags.behavior;
         return getNavigationBar() != null
                 && canHideNavigationBar()
-                && (behavior == BEHAVIOR_SHOW_BARS_BY_SWIPE
-                        || behavior == BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE)
                 && getInsetsPolicy().isHidden(ITYPE_NAVIGATION_BAR)
                 && win != getNotificationShade()
                 && !win.isActivityTypeDream();
@@ -3177,4 +3090,26 @@
 
         return Rect.intersects(targetWindow.getFrame(), navBarWindow.getFrame());
     }
+
+    /**
+     * @return Whether we should attach navigation bar to the app during transition.
+     */
+    boolean shouldAttachNavBarToAppDuringTransition() {
+        return mShouldAttachNavBarToAppDuringTransition && mNavigationBar != null;
+    }
+
+    @Nullable NavBarFadeAnimationController getNavBarFadeAnimationController() {
+        return mNavBarFadeAnimationController;
+    }
+
+    private void updateNavBarFadeController() {
+        if (shouldAttachNavBarToAppDuringTransition()) {
+            if (mNavBarFadeAnimationController == null) {
+                mNavBarFadeAnimationController =
+                        new NavBarFadeAnimationController(mDisplayContent);
+            }
+        } else {
+            mNavBarFadeAnimationController = null;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index c4aaf7c..df5d3ea3 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -955,10 +955,16 @@
                 keyguardDrawComplete, windowManagerDrawComplete);
 
         boolean disable = true;
+
+        // If the orientation listener uses a wake sensor, keep the orientation listener on if the
+        // screen is on (regardless of wake state). This allows the AoD to rotate.
+        //
         // Note: We postpone the rotating of the screen until the keyguard as well as the
         // window manager have reported a draw complete or the keyguard is going away in dismiss
         // mode.
-        if (screenOnEarly && awake && ((keyguardDrawComplete && windowManagerDrawComplete))) {
+        if (screenOnEarly
+                && (awake || mOrientationListener.shouldStayEnabledWhileDreaming())
+                && ((keyguardDrawComplete && windowManagerDrawComplete))) {
             if (needSensorRunning()) {
                 disable = false;
                 // Enable listener if not already enabled.
@@ -974,7 +980,7 @@
             }
         }
         // Check if sensors need to be disabled.
-        if (disable && mOrientationListener.mEnabled) {
+        if (disable) {
             mOrientationListener.disable();
         }
     }
diff --git a/services/core/java/com/android/server/wm/FadeAnimationController.java b/services/core/java/com/android/server/wm/FadeAnimationController.java
new file mode 100644
index 0000000..17d20ae
--- /dev/null
+++ b/services/core/java/com/android/server/wm/FadeAnimationController.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static com.android.server.wm.AnimationSpecProto.WINDOW;
+import static com.android.server.wm.WindowAnimationSpecProto.ANIMATION;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.util.ArrayMap;
+import android.util.proto.ProtoOutputStream;
+import android.view.SurfaceControl;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Transformation;
+
+import com.android.internal.R;
+
+import java.io.PrintWriter;
+
+/**
+ * An animation controller to fade-in/out for a window token.
+ */
+public class FadeAnimationController {
+    protected final Context mContext;
+    private final ArrayMap<WindowToken, Runnable> mDeferredFinishCallbacks = new ArrayMap<>();
+
+    public FadeAnimationController(DisplayContent displayContent) {
+        mContext = displayContent.mWmService.mContext;
+    }
+
+    /**
+     * @return a fade-in Animation.
+     */
+    public Animation getFadeInAnimation() {
+        return AnimationUtils.loadAnimation(mContext, R.anim.fade_in);
+    }
+
+    /**
+     * @return a fade-out Animation.
+     */
+    public Animation getFadeOutAnimation() {
+        return AnimationUtils.loadAnimation(mContext, R.anim.fade_out);
+    }
+
+    /**
+     * Run the fade in/out animation for a window token.
+     *
+     * @param show true for fade-in, otherwise for fade-out.
+     * @param windowToken the window token to run the animation.
+     * @param animationType the animation type defined in SurfaceAnimator.
+     */
+    public void fadeWindowToken(boolean show, WindowToken windowToken, int animationType) {
+        if (windowToken == null || windowToken.getParent() == null) {
+            return;
+        }
+
+        final Animation animation = show ? getFadeInAnimation() : getFadeOutAnimation();
+        if (animation == null) {
+            return;
+        }
+
+        final LocalAnimationAdapter.AnimationSpec windowAnimationSpec =
+                createAnimationSpec(animation);
+
+        final FadeAnimationAdapter animationAdapter = new FadeAnimationAdapter(
+                windowAnimationSpec, windowToken.getSurfaceAnimationRunner(), show, windowToken);
+
+        // We deferred the end of the animation when hiding the token, so we need to end it now that
+        // it's shown again.
+        final SurfaceAnimator.OnAnimationFinishedCallback finishedCallback = show ? (t, r) -> {
+            final Runnable runnable = mDeferredFinishCallbacks.remove(windowToken);
+            if (runnable != null) {
+                runnable.run();
+            }
+        } : null;
+        windowToken.startAnimation(windowToken.getPendingTransaction(), animationAdapter,
+                show /* hidden */, animationType, finishedCallback);
+    }
+
+    private LocalAnimationAdapter.AnimationSpec createAnimationSpec(@NonNull Animation animation) {
+        return new LocalAnimationAdapter.AnimationSpec() {
+
+            final Transformation mTransformation = new Transformation();
+
+            @Override
+            public boolean getShowWallpaper() {
+                return true;
+            }
+
+            @Override
+            public long getDuration() {
+                return animation.getDuration();
+            }
+
+            @Override
+            public void apply(SurfaceControl.Transaction t, SurfaceControl leash,
+                    long currentPlayTime) {
+                mTransformation.clear();
+                animation.getTransformation(currentPlayTime, mTransformation);
+                t.setAlpha(leash, mTransformation.getAlpha());
+            }
+
+            @Override
+            public void dump(PrintWriter pw, String prefix) {
+                pw.print(prefix);
+                pw.println(animation);
+            }
+
+            @Override
+            public void dumpDebugInner(ProtoOutputStream proto) {
+                final long token = proto.start(WINDOW);
+                proto.write(ANIMATION, animation.toString());
+                proto.end(token);
+            }
+        };
+    }
+
+    private class FadeAnimationAdapter extends LocalAnimationAdapter {
+        private final boolean mShow;
+        private final WindowToken mToken;
+
+        FadeAnimationAdapter(AnimationSpec windowAnimationSpec,
+                SurfaceAnimationRunner surfaceAnimationRunner, boolean show,
+                WindowToken token) {
+            super(windowAnimationSpec, surfaceAnimationRunner);
+            mShow = show;
+            mToken = token;
+        }
+
+        @Override
+        public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) {
+            // We defer the end of the hide animation to ensure the tokens stay hidden until
+            // we show them again.
+            if (!mShow) {
+                mDeferredFinishCallbacks.put(mToken, endDeferFinishCallback);
+                return true;
+            }
+            return false;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/FixedRotationAnimationController.java b/services/core/java/com/android/server/wm/FixedRotationAnimationController.java
index cc02e99..a1e3ac7 100644
--- a/services/core/java/com/android/server/wm/FixedRotationAnimationController.java
+++ b/services/core/java/com/android/server/wm/FixedRotationAnimationController.java
@@ -16,21 +16,8 @@
 
 package com.android.server.wm;
 
-import static com.android.server.wm.AnimationSpecProto.WINDOW;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_FIXED_TRANSFORM;
-import static com.android.server.wm.WindowAnimationSpecProto.ANIMATION;
 
-import android.content.Context;
-import android.util.ArrayMap;
-import android.util.proto.ProtoOutputStream;
-import android.view.SurfaceControl;
-import android.view.animation.Animation;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Transformation;
-
-import com.android.internal.R;
-
-import java.io.PrintWriter;
 import java.util.ArrayList;
 
 /**
@@ -40,16 +27,14 @@
  * The system bars will be fade out when the fixed rotation transform starts and will be fade in
  * once all surfaces have been rotated.
  */
-public class FixedRotationAnimationController {
+public class FixedRotationAnimationController extends FadeAnimationController {
 
-    private final Context mContext;
     private final WindowState mStatusBar;
     private final WindowState mNavigationBar;
     private final ArrayList<WindowToken> mAnimatedWindowToken = new ArrayList<>(2);
-    private final ArrayMap<WindowToken, Runnable> mDeferredFinishCallbacks = new ArrayMap<>();
 
     public FixedRotationAnimationController(DisplayContent displayContent) {
-        mContext = displayContent.mWmService.mContext;
+        super(displayContent);
         final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
         mStatusBar = displayPolicy.getStatusBar();
         // Do not animate movable navigation bar (e.g. non-gesture mode).
@@ -62,105 +47,25 @@
     void show() {
         for (int i = mAnimatedWindowToken.size() - 1; i >= 0; i--) {
             final WindowToken windowToken = mAnimatedWindowToken.get(i);
-            fadeWindowToken(true /* show */, windowToken);
+            fadeWindowToken(true /* show */, windowToken, ANIMATION_TYPE_FIXED_TRANSFORM);
         }
     }
 
     /** Applies hide animation on the window tokens which may be seamlessly rotated later. */
     void hide() {
         if (mNavigationBar != null) {
-            fadeWindowToken(false /* show */, mNavigationBar.mToken);
+            fadeWindowToken(false /* show */, mNavigationBar.mToken,
+                    ANIMATION_TYPE_FIXED_TRANSFORM);
         }
         if (mStatusBar != null) {
-            fadeWindowToken(false /* show */, mStatusBar.mToken);
+            fadeWindowToken(false /* show */, mStatusBar.mToken,
+                    ANIMATION_TYPE_FIXED_TRANSFORM);
         }
     }
 
-    private void fadeWindowToken(boolean show, WindowToken windowToken) {
-        if (windowToken == null || windowToken.getParent() == null) {
-            return;
-        }
-
-        final Animation animation = AnimationUtils.loadAnimation(mContext,
-                show ? R.anim.fade_in : R.anim.fade_out);
-        final LocalAnimationAdapter.AnimationSpec windowAnimationSpec =
-                createAnimationSpec(animation);
-
-        final FixedRotationAnimationAdapter animationAdapter = new FixedRotationAnimationAdapter(
-                windowAnimationSpec, windowToken.getSurfaceAnimationRunner(), show, windowToken);
-
-        // We deferred the end of the animation when hiding the token, so we need to end it now that
-        // it's shown again.
-        final SurfaceAnimator.OnAnimationFinishedCallback finishedCallback = show ? (t, r) -> {
-            final Runnable runnable = mDeferredFinishCallbacks.remove(windowToken);
-            if (runnable != null) {
-                runnable.run();
-            }
-        } : null;
-        windowToken.startAnimation(windowToken.getPendingTransaction(), animationAdapter,
-                show /* hidden */, ANIMATION_TYPE_FIXED_TRANSFORM, finishedCallback);
+    @Override
+    public void fadeWindowToken(boolean show, WindowToken windowToken, int animationType) {
+        super.fadeWindowToken(show, windowToken, animationType);
         mAnimatedWindowToken.add(windowToken);
     }
-
-    private LocalAnimationAdapter.AnimationSpec createAnimationSpec(Animation animation) {
-        return new LocalAnimationAdapter.AnimationSpec() {
-
-            final Transformation mTransformation = new Transformation();
-
-            @Override
-            public boolean getShowWallpaper() {
-                return true;
-            }
-
-            @Override
-            public long getDuration() {
-                return animation.getDuration();
-            }
-
-            @Override
-            public void apply(SurfaceControl.Transaction t, SurfaceControl leash,
-                    long currentPlayTime) {
-                mTransformation.clear();
-                animation.getTransformation(currentPlayTime, mTransformation);
-                t.setAlpha(leash, mTransformation.getAlpha());
-            }
-
-            @Override
-            public void dump(PrintWriter pw, String prefix) {
-                pw.print(prefix);
-                pw.println(animation);
-            }
-
-            @Override
-            public void dumpDebugInner(ProtoOutputStream proto) {
-                final long token = proto.start(WINDOW);
-                proto.write(ANIMATION, animation.toString());
-                proto.end(token);
-            }
-        };
-    }
-
-    private class FixedRotationAnimationAdapter extends LocalAnimationAdapter {
-        private final boolean mShow;
-        private final WindowToken mToken;
-
-        FixedRotationAnimationAdapter(AnimationSpec windowAnimationSpec,
-                SurfaceAnimationRunner surfaceAnimationRunner, boolean show,
-                WindowToken token) {
-            super(windowAnimationSpec, surfaceAnimationRunner);
-            mShow = show;
-            mToken = token;
-        }
-
-        @Override
-        public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) {
-            // We defer the end of the hide animation to ensure the tokens stay hidden until
-            // we show them again.
-            if (!mShow) {
-                mDeferredFinishCallbacks.put(mToken, endDeferFinishCallback);
-                return true;
-            }
-            return false;
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 560547e..a20d924 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -19,7 +19,6 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.Display.INVALID_DISPLAY;
-import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION;
 import static android.view.WindowManager.INPUT_CONSUMER_PIP;
 import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
 import static android.view.WindowManager.INPUT_CONSUMER_WALLPAPER;
@@ -53,7 +52,6 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
-import android.os.Process;
 import android.os.Trace;
 import android.os.UserHandle;
 import android.util.ArrayMap;
@@ -232,24 +230,6 @@
         }
     }
 
-    EventReceiverInputConsumer createInputConsumer(Looper looper, String name,
-            InputEventReceiver.Factory inputEventReceiverFactory) {
-        if (!name.contentEquals(INPUT_CONSUMER_NAVIGATION)) {
-            throw new IllegalArgumentException("Illegal input consumer : " + name
-                    + ", display: " + mDisplayId);
-        }
-
-        if (mInputConsumers.containsKey(name)) {
-            throw new IllegalStateException("Existing input consumer found with name: " + name
-                    + ", display: " + mDisplayId);
-        }
-        final EventReceiverInputConsumer consumer = new EventReceiverInputConsumer(mService,
-                this, looper, name, inputEventReceiverFactory, Process.myPid(),
-                UserHandle.SYSTEM, mDisplayId);
-        addInputConsumer(name, consumer);
-        return consumer;
-    }
-
     void createInputConsumer(IBinder token, String name, InputChannel inputChannel, int clientPid,
             UserHandle clientUser) {
         if (mInputConsumers.containsKey(name)) {
@@ -472,12 +452,10 @@
     }
 
     private final class UpdateInputForAllWindowsConsumer implements Consumer<WindowState> {
-        InputConsumerImpl mNavInputConsumer;
         InputConsumerImpl mPipInputConsumer;
         InputConsumerImpl mWallpaperInputConsumer;
         InputConsumerImpl mRecentsAnimationInputConsumer;
 
-        private boolean mAddNavInputConsumerHandle;
         private boolean mAddPipInputConsumerHandle;
         private boolean mAddWallpaperInputConsumerHandle;
         private boolean mAddRecentsAnimationInputConsumerHandle;
@@ -487,12 +465,10 @@
         private void updateInputWindows(boolean inDrag) {
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateInputWindows");
 
-            mNavInputConsumer = getInputConsumer(INPUT_CONSUMER_NAVIGATION);
             mPipInputConsumer = getInputConsumer(INPUT_CONSUMER_PIP);
             mWallpaperInputConsumer = getInputConsumer(INPUT_CONSUMER_WALLPAPER);
             mRecentsAnimationInputConsumer = getInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION);
 
-            mAddNavInputConsumerHandle = mNavInputConsumer != null;
             mAddPipInputConsumerHandle = mPipInputConsumer != null;
             mAddWallpaperInputConsumerHandle = mWallpaperInputConsumer != null;
             mAddRecentsAnimationInputConsumerHandle = mRecentsAnimationInputConsumer != null;
@@ -557,12 +533,6 @@
                 }
             }
 
-            if (mAddNavInputConsumerHandle) {
-                // We set the layer to z=MAX-1 so that it's always on top.
-                mNavInputConsumer.show(mInputTransaction, Integer.MAX_VALUE - 1);
-                mAddNavInputConsumerHandle = false;
-            }
-
             if (mAddWallpaperInputConsumerHandle) {
                 if (w.mAttrs.type == TYPE_WALLPAPER && w.isVisible()) {
                     // Add the wallpaper input consumer above the first visible wallpaper.
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index ee150c3..94a7ebd 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -142,7 +142,6 @@
                 getFakeControlTarget(focusedWin, navControlTarget));
         mStatusBar.updateVisibility(statusControlTarget, ITYPE_STATUS_BAR);
         mNavBar.updateVisibility(navControlTarget, ITYPE_NAVIGATION_BAR);
-        mPolicy.updateHideNavInputEventReceiver();
     }
 
     boolean isHidden(@InternalInsetsType int type) {
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 40e7a8e..0dfa2d8 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -152,6 +152,7 @@
             // animate-out as new one animates-in.
             mWin.cancelAnimation();
             mWin.mPendingPositionChanged = null;
+            mWin.mProvidedInsetsSources.remove(mSource.getType());
         }
         ProtoLog.d(WM_DEBUG_IME, "InsetsSource setWin %s", win);
         mWin = win;
@@ -161,11 +162,14 @@
             setServerVisible(false);
             mSource.setFrame(new Rect());
             mSource.setVisibleFrame(null);
-        } else if (mControllable) {
-            mWin.setControllableInsetProvider(this);
-            if (mPendingControlTarget != null) {
-                updateControlForTarget(mPendingControlTarget, true /* force */);
-                mPendingControlTarget = null;
+        } else {
+            mWin.mProvidedInsetsSources.put(mSource.getType(), mSource);
+            if (mControllable) {
+                mWin.setControllableInsetProvider(this);
+                if (mPendingControlTarget != null) {
+                    updateControlForTarget(mPendingControlTarget, true /* force */);
+                    mPendingControlTarget = null;
+                }
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 752d6b4..a1461b2 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -104,6 +104,8 @@
      * visible to the target. e.g., the source which represents the target window itself, and the
      * IME source when the target is above IME. We also need to exclude certain types of insets
      * source for client within specific windowing modes.
+     * This is to get the insets for a window layout on the screen. If the window is not there, use
+     * the {@link #getInsetsForWindowMetrics} to get insets instead.
      *
      * @param target The window associate with the perspective.
      * @return The state stripped of the necessary information.
@@ -117,7 +119,7 @@
         final @InternalInsetsType int type = provider != null
                 ? provider.getSource().getType() : ITYPE_INVALID;
         return getInsetsForTarget(type, target.getWindowingMode(), target.isAlwaysOnTop(),
-                isAboveIme(target));
+                target.mAboveInsetsState);
     }
 
     InsetsState getInsetsForWindowMetrics(@NonNull WindowManager.LayoutParams attrs) {
@@ -132,19 +134,7 @@
         final @WindowingMode int windowingMode = token != null
                 ? token.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
         final boolean alwaysOnTop = token != null && token.isAlwaysOnTop();
-        return getInsetsForTarget(type, windowingMode, alwaysOnTop, isAboveIme(token));
-    }
-
-    private boolean isAboveIme(WindowContainer target) {
-        final WindowState imeWindow = mDisplayContent.mInputMethodWindow;
-        if (target == null || imeWindow == null) {
-            return false;
-        }
-        if (target instanceof WindowState) {
-            final WindowState win = (WindowState) target;
-            return win.needsRelativeLayeringToIme() || !win.mBehindIme;
-        }
-        return false;
+        return getInsetsForTarget(type, windowingMode, alwaysOnTop, mState);
     }
 
     private static @InternalInsetsType
@@ -180,11 +170,12 @@
      * @see #getInsetsForWindowMetrics
      */
     private InsetsState getInsetsForTarget(@InternalInsetsType int type,
-            @WindowingMode int windowingMode, boolean isAlwaysOnTop, boolean aboveIme) {
-        InsetsState state = mState;
+            @WindowingMode int windowingMode, boolean isAlwaysOnTop, InsetsState state) {
+        boolean stateCopied = false;
 
         if (type != ITYPE_INVALID) {
             state = new InsetsState(state);
+            stateCopied = true;
             state.removeSource(type);
 
             // Navigation bar doesn't get influenced by anything else
@@ -219,23 +210,15 @@
 
         if (WindowConfiguration.isFloating(windowingMode)
                 || (windowingMode == WINDOWING_MODE_MULTI_WINDOW && isAlwaysOnTop)) {
-            state = new InsetsState(state);
+            if (!stateCopied) {
+                state = new InsetsState(state);
+                stateCopied = true;
+            }
             state.removeSource(ITYPE_STATUS_BAR);
             state.removeSource(ITYPE_NAVIGATION_BAR);
             state.removeSource(ITYPE_EXTRA_NAVIGATION_BAR);
         }
 
-        if (aboveIme) {
-            InsetsSource imeSource = state.peekSource(ITYPE_IME);
-            if (imeSource != null && imeSource.isVisible()) {
-                imeSource = new InsetsSource(imeSource);
-                imeSource.setVisible(false);
-                imeSource.setFrame(0, 0, 0, 0);
-                state = new InsetsState(state);
-                state.addSource(imeSource);
-            }
-        }
-
         return state;
     }
 
diff --git a/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java b/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java
new file mode 100644
index 0000000..30861eb
--- /dev/null
+++ b/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
+
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
+
+/**
+ * Controller to fade in and out  navigation bar during app transition when
+ * config_attachNavBarToAppDuringTransition is true.
+ */
+public class NavBarFadeAnimationController extends FadeAnimationController{
+    private static final int FADE_IN_DURATION = 266;
+    private static final int FADE_OUT_DURATION = 133;
+    private static final Interpolator FADE_IN_INTERPOLATOR =
+            new PathInterpolator(0f, 0f, 0f, 1f);
+    private static final Interpolator FADE_OUT_INTERPOLATOR =
+            new PathInterpolator(0.2f, 0f, 1f, 1f);
+
+    private final WindowState mNavigationBar;
+    private Animation mFadeInAnimation;
+    private Animation mFadeOutAnimation;
+
+    public NavBarFadeAnimationController(DisplayContent displayContent) {
+        super(displayContent);
+        mNavigationBar = displayContent.getDisplayPolicy().getNavigationBar();
+        mFadeInAnimation = new AlphaAnimation(0f, 1f);
+        mFadeInAnimation.setDuration(FADE_IN_DURATION);
+        mFadeInAnimation.setInterpolator(FADE_IN_INTERPOLATOR);
+
+        mFadeOutAnimation = new AlphaAnimation(1f, 0f);
+        mFadeOutAnimation.setDuration(FADE_OUT_DURATION);
+        mFadeOutAnimation.setInterpolator(FADE_OUT_INTERPOLATOR);
+    }
+
+    @Override
+    public Animation getFadeInAnimation() {
+        return mFadeInAnimation;
+    }
+
+    @Override
+    public Animation getFadeOutAnimation() {
+        return mFadeOutAnimation;
+    }
+
+    /**
+     * Run the fade-in/out animation for the navigation bar.
+     *
+     * @param show true for fade-in, otherwise for fade-out.
+     */
+    public void fadeWindowToken(boolean show) {
+        fadeWindowToken(show, mNavigationBar.mToken, ANIMATION_TYPE_APP_TRANSITION);
+    }
+}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 388577c..00b6ceb 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -33,7 +33,6 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.window.TaskSnapshot;
 import android.app.WindowConfiguration;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -54,6 +53,7 @@
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
 import android.view.WindowInsets.Type;
+import android.window.TaskSnapshot;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.inputmethod.SoftInputShowHideReason;
@@ -147,6 +147,9 @@
     // Whether to take a screenshot when handling a deferred cancel
     private boolean mCancelDeferredWithScreenshot;
 
+    @VisibleForTesting
+    boolean mShouldAttachNavBarToAppDuringTransition;
+
     /**
      * Animates the screenshot of task that used to be controlled by RecentsAnimation.
      * @see {@link #setCancelOnNextTransitionStart}
@@ -390,6 +393,8 @@
         mDisplayId = displayId;
         mStatusBar = LocalServices.getService(StatusBarManagerInternal.class);
         mDisplayContent = service.mRoot.getDisplayContent(displayId);
+        mShouldAttachNavBarToAppDuringTransition =
+                mDisplayContent.getDisplayPolicy().shouldAttachNavBarToAppDuringTransition();
     }
 
     /**
@@ -439,6 +444,10 @@
             return;
         }
 
+        if (mShouldAttachNavBarToAppDuringTransition) {
+            attachNavBarToApp();
+        }
+
         // Adjust the wallpaper visibility for the showing target activity
         ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
                 "setHomeApp(%s)", targetActivity.getName());
@@ -572,6 +581,63 @@
         }
     }
 
+    @VisibleForTesting
+    WindowToken getNavigationBarWindowToken() {
+        WindowState navBar = mDisplayContent.getDisplayPolicy().getNavigationBar();
+        if (navBar != null) {
+            return navBar.mToken;
+        }
+        return null;
+    }
+
+    private void attachNavBarToApp() {
+        ActivityRecord topActivity = null;
+        for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
+            final TaskAnimationAdapter adapter = mPendingAnimations.get(i);
+            final Task task = adapter.mTask;
+            if (!task.isHomeOrRecentsRootTask()) {
+                topActivity = task.getTopVisibleActivity();
+                break;
+            }
+        }
+        final WindowToken navToken = getNavigationBarWindowToken();
+        if (topActivity == null || navToken == null) {
+            return;
+        }
+
+        final SurfaceControl.Transaction t = navToken.getPendingTransaction();
+        final SurfaceControl navSurfaceControl = navToken.getSurfaceControl();
+        t.reparent(navSurfaceControl, topActivity.getSurfaceControl());
+        t.show(navSurfaceControl);
+
+        final WindowContainer imeContainer = mDisplayContent.getImeContainer();
+        if (imeContainer.isVisible()) {
+            t.setRelativeLayer(navSurfaceControl, imeContainer.getSurfaceControl(), 1);
+        } else {
+            // Place the nav bar on top of anything else in the top activity.
+            t.setLayer(navSurfaceControl, Integer.MAX_VALUE);
+        }
+    }
+
+    private void restoreNavBarFromApp(boolean animate) {
+        // Reparent the SurfaceControl of nav bar token back.
+        final WindowToken navToken = getNavigationBarWindowToken();
+        final SurfaceControl.Transaction t = mDisplayContent.getPendingTransaction();
+        if (navToken != null) {
+            final WindowContainer parent = navToken.getParent();
+            t.reparent(navToken.getSurfaceControl(), parent.getSurfaceControl());
+        }
+
+        if (animate) {
+            // Run fade-in animation to show navigation bar back to bottom of the display.
+            final NavBarFadeAnimationController controller =
+                    mDisplayContent.getDisplayPolicy().getNavBarFadeAnimationController();
+            if (controller != null) {
+                controller.fadeWindowToken(true);
+            }
+        }
+    }
+
     void addTaskToTargets(Task task, OnAnimationFinishedCallback finishedCallback) {
         if (mRunner != null) {
             // No need to send task appeared when the task target already exists, or when the
@@ -790,6 +856,10 @@
             removeWallpaperAnimation(wallpaperAdapter);
         }
 
+        if (mShouldAttachNavBarToAppDuringTransition) {
+            restoreNavBarFromApp(reorderMode == REORDER_MOVE_TO_TOP);
+        }
+
         // Clear any pending failsafe runnables
         mService.mH.removeCallbacks(mFailsafeRunnable);
         mDisplayContent.mAppTransition.unregisterListener(mAppTransitionListener);
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 23acbf7..d8b1e18 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -862,6 +862,9 @@
                         "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
             }
         }
+
+        // Send any pending task-info changes that were queued-up during a layout deferment
+        mWmService.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         mWmService.mAnimator.executeAfterPrepareSurfacesRunnables();
 
         checkAppTransitionReady(surfacePlacer);
@@ -1014,9 +1017,6 @@
 
         mWmService.scheduleAnimationLocked();
 
-        // Send any pending task-info changes that were queued-up during a layout deferment
-        mWmService.mAtmService.mTaskOrganizerController.dispatchPendingTaskInfoChanges();
-
         if (DEBUG_WINDOW_TRACE) Slog.e(TAG, "performSurfacePlacementInner exit");
     }
 
@@ -1545,6 +1545,8 @@
             homeIntent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, true);
             mWindowManager.cancelRecentsAnimation(REORDER_KEEP_IN_PLACE, "startHomeActivity");
         }
+        homeIntent.putExtra(WindowManagerPolicy.EXTRA_START_REASON, reason);
+
         // Update the reason for ANR debugging to verify if the user activity is the one that
         // actually launched.
         final String myReason = reason + ":" + userId + ":" + UserHandle.getUserId(
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 1a27b1b..533c82e 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -206,12 +206,17 @@
                     .setCallsite("ScreenRotationAnimation")
                     .build();
 
+            String name = "RotationLayer";
             mScreenshotLayer = displayContent.makeOverlay()
-                    .setName("RotationLayer")
+                    .setName(name)
                     .setBufferSize(mWidth, mHeight)
                     .setSecure(isSecure)
                     .setCallsite("ScreenRotationAnimation")
                     .build();
+            // This is the way to tell the input system to exclude this surface from occlusion
+            // detection since we don't have a window for it. We do this because this window is
+            // generated by the system as well as its content.
+            InputMonitor.setTrustedOverlayInputInfo(mScreenshotLayer, t, displayId, name);
 
             mEnterBlackFrameLayer = displayContent.makeOverlay()
                     .setName("EnterBlackFrameLayer")
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 637240c..855c8f5 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -424,6 +424,9 @@
     /** If original intent did not allow relinquishing task identity, save that information */
     private boolean mNeverRelinquishIdentity = true;
 
+    /** Avoid reentrant of {@link #removeImmediately(String)}. */
+    private boolean mRemoving;
+
     // Used in the unique case where we are clearing the task in order to reuse it. In that case we
     // do not want to delete the stack when the task goes empty.
     private boolean mReuseTask = false;
@@ -2825,9 +2828,7 @@
                 getResolvedOverrideConfiguration().windowConfiguration.getBounds();
 
         if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
-            computeFullscreenBounds(outOverrideBounds, null /* refActivity */,
-                    newParentConfig.windowConfiguration.getBounds(),
-                    newParentConfig.orientation);
+            computeFullscreenBounds(outOverrideBounds, newParentConfig);
             // The bounds for fullscreen mode shouldn't be adjusted by minimal size. Otherwise if
             // the parent or display is smaller than the size, the content may be cropped.
             return;
@@ -2867,19 +2868,19 @@
      * {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN} when the parent doesn't handle the
      * orientation change and the requested orientation is different from the parent.
      */
-    void computeFullscreenBounds(@NonNull Rect outBounds, @Nullable ActivityRecord refActivity,
-            @NonNull Rect parentBounds, int parentOrientation) {
+    void computeFullscreenBounds(@NonNull Rect outBounds, @NonNull Configuration newParentConfig) {
         // In FULLSCREEN mode, always start with empty bounds to indicate "fill parent".
         outBounds.setEmpty();
         if (handlesOrientationChangeFromDescendant()) {
+            // No need to letterbox at task level. Display will handle fixed-orientation requests.
             return;
         }
-        if (refActivity == null) {
-            // Use the top activity as the reference of orientation. Don't include overlays because
-            // it is usually not the actual content or just temporarily shown.
-            // E.g. ForcedResizableInfoActivity.
-            refActivity = getTopNonFinishingActivity(false /* includeOverlays */);
-        }
+
+        final int parentOrientation = newParentConfig.orientation;
+        // Use the top activity as the reference of orientation. Don't include overlays because
+        // it is usually not the actual content or just temporarily shown.
+        // E.g. ForcedResizableInfoActivity.
+        final ActivityRecord refActivity = getTopNonFinishingActivity(false /* includeOverlays */);
 
         // If the task or the reference activity requires a different orientation (either by
         // override or activityInfo), make it fit the available bounds by scaling down its bounds.
@@ -2891,11 +2892,17 @@
             return;
         }
 
-        if (refActivity != null && refActivity.hasCompatDisplayInsets()) {
+        final ActivityRecord.CompatDisplayInsets compatDisplayInsets =
+                refActivity == null ? null : refActivity.getCompatDisplayInsets();
+        if (compatDisplayInsets != null && !compatDisplayInsets.mIsTaskLetterboxed) {
             // App prefers to keep its original size.
+            // If the size compat is from previous task letterboxing, we may want to have task
+            // letterbox again, otherwise it will show the size compat restart button even if the
+            // restart bounds will be the same.
             return;
         }
 
+        final Rect parentBounds = newParentConfig.windowConfiguration.getBounds();
         final int parentWidth = parentBounds.width();
         final int parentHeight = parentBounds.height();
         float aspect = Math.max(parentWidth, parentHeight)
@@ -2930,6 +2937,18 @@
             final int left = parentBounds.centerX() - width / 2;
             outBounds.set(left, parentBounds.top, left + width, parentBounds.bottom);
         }
+
+        if (compatDisplayInsets != null) {
+            compatDisplayInsets.getBoundsByRotation(
+                    mTmpBounds, newParentConfig.windowConfiguration.getRotation());
+            if (outBounds.width() != mTmpBounds.width()
+                    || outBounds.height() != mTmpBounds.height()) {
+                // The app shouldn't be resized, we only do task letterboxing if the compat bounds
+                // is also from the same task letterbox. Otherwise, clear the task bounds to show
+                // app in size compat mode.
+                outBounds.setEmpty();
+            }
+        }
     }
 
     Rect updateOverrideConfigurationFromLaunchBounds() {
@@ -3223,12 +3242,18 @@
 
     void removeImmediately(String reason) {
         if (DEBUG_ROOT_TASK) Slog.i(TAG, "removeTask:" + reason + " removing taskId=" + mTaskId);
+        if (mRemoving) {
+            return;
+        }
+        mRemoving = true;
+
         EventLogTags.writeWmTaskRemoved(mTaskId, reason);
 
         // If applicable let the TaskOrganizer know the Task is vanishing.
         setTaskOrganizer(null);
 
         super.removeImmediately();
+        mRemoving = false;
     }
 
     // TODO: Consolidate this with Task.reparent()
@@ -3304,6 +3329,14 @@
         return false;
     }
 
+    @Override
+    boolean handlesOrientationChangeFromDescendant() {
+        return super.handlesOrientationChangeFromDescendant()
+                // Display won't rotate for the orientation request if the TaskDisplayArea can't
+                // specify orientation.
+                && getDisplayArea().canSpecifyOrientation();
+    }
+
     void resize(boolean relayout, boolean forced) {
         if (setBounds(getRequestedOverrideBounds(), forced) != BOUNDS_CHANGE_NONE && relayout) {
             getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
@@ -4993,7 +5026,6 @@
             }
         } else {
             // No longer managed by any organizer.
-            mTaskAppearedSent = false;
             setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, false /* set */);
             if (mCreatedByOrganizer) {
                 removeImmediately("setTaskOrganizer");
@@ -5019,7 +5051,7 @@
      */
     boolean updateTaskOrganizerState(boolean forceUpdate, boolean skipTaskAppeared) {
         if (getSurfaceControl() == null) {
-            // Can't call onTaskAppeared without a surfacecontrol, so defer this until after one
+            // Can't call onTaskAppeared without a surfacecontrol, so defer this until next one
             // is created.
             return false;
         }
@@ -6036,8 +6068,6 @@
         // If the top activity is the resumed one, nothing to do.
         if (mResumedActivity == next && next.isState(RESUMED)
                 && taskDisplayArea.allResumedActivitiesComplete()) {
-            // The activity may be waiting for stop, but that is no longer appropriate for it.
-            mTaskSupervisor.mStoppingActivities.remove(next);
             // Make sure we have executed any pending transitions, since there
             // should be nothing left to do at this point.
             executeAppTransition(options);
@@ -7167,6 +7197,7 @@
                     + " mode=" + windowingModeToString(getWindowingMode()));
             pw.println("  isSleeping=" + shouldSleepActivities());
             pw.println("  mBounds=" + getRequestedOverrideBounds());
+            pw.println("  mCreatedByOrganizer=" + mCreatedByOrganizer);
         };
 
         boolean printed = false;
@@ -7672,7 +7703,7 @@
 
     void dispatchTaskInfoChangedIfNeeded(boolean force) {
         if (isOrganized()) {
-            mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(this, force);
+            mAtmService.mTaskOrganizerController.onTaskInfoChanged(this, force);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 832fc68..0136c01 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -19,7 +19,6 @@
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
@@ -60,6 +59,7 @@
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.function.BiFunction;
 import java.util.function.Consumer;
@@ -1848,9 +1848,6 @@
         // Keep the order from bottom to top.
         int numRootTasks = mChildren.size();
 
-        final boolean splitScreenActivated = toDisplayArea.isSplitScreenModeActivated();
-        final Task splitScreenRoot = splitScreenActivated ? toDisplayArea
-                .getTopRootTaskInWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) : null;
         for (int i = 0; i < numRootTasks; i++) {
             final WindowContainer child = mChildren.get(i);
             if (child.asTaskDisplayArea() != null) {
@@ -1866,10 +1863,12 @@
                     || task.mCreatedByOrganizer) {
                 task.finishAllActivitiesImmediately();
             } else {
-                // Reparent the root task to the root task of secondary-split-screen or display
-                // area.
-                task.reparent(task.supportsSplitScreenWindowingMode() && splitScreenRoot != null
-                        ? splitScreenRoot : toDisplayArea, POSITION_TOP);
+                // Reparent task to corresponding launch root or display area.
+                final WindowContainer launchRoot = task.supportsSplitScreenWindowingMode()
+                        ? toDisplayArea.getLaunchRootTask(
+                                task.getWindowingMode(), task.getActivityType())
+                        : null;
+                task.reparent(launchRoot == null ? toDisplayArea : launchRoot, POSITION_TOP);
 
                 // Set the windowing mode to undefined by default to let the root task inherited the
                 // windowing mode.
@@ -1881,14 +1880,19 @@
             i -= numRootTasks - mChildren.size();
             numRootTasks = mChildren.size();
         }
-        if (lastReparentedRootTask != null && splitScreenActivated) {
-            if (!lastReparentedRootTask.supportsSplitScreenWindowingMode()) {
+
+        if (lastReparentedRootTask != null) {
+            if (toDisplayArea.isSplitScreenModeActivated()
+                    && !lastReparentedRootTask.supportsSplitScreenWindowingMode()) {
+                // Dismiss split screen if the last reparented root task doesn't support split mode.
                 mAtmService.getTaskChangeNotificationController()
                         .notifyActivityDismissingDockedStack();
                 toDisplayArea.onSplitScreenModeDismissed(lastReparentedRootTask);
-            } else if (splitScreenRoot != null) {
-                // update focus
-                splitScreenRoot.moveToFront("display-removed");
+            } else if (!lastReparentedRootTask.isRootTask()) {
+                // Update focus when the last reparented root task is not a root task anymore.
+                // (For example, if it has been reparented to a split screen root task, move the
+                // focus to the split root task)
+                lastReparentedRootTask.getRootTask().moveToFront("display-removed");
             }
         }
 
@@ -1898,7 +1902,6 @@
     }
 
     /** Whether this task display area can request orientation. */
-    @VisibleForTesting
     boolean canSpecifyOrientation() {
         // Only allow to specify orientation if this TDA is not set to ignore orientation request,
         // and it is the last focused one on this logical display that can request orientation
@@ -1937,8 +1940,8 @@
             for (int i = mLaunchRootTasks.size() - 1; i >= 0; --i) {
                 final LaunchRootTaskDef def = mLaunchRootTasks.get(i);
                 pw.println(triplePrefix
-                        + def.activityTypes + " "
-                        + def.windowingModes + " "
+                        + Arrays.toString(def.activityTypes) + " "
+                        + Arrays.toString(def.windowingModes) + " "
                         + " task=" + def.task);
             }
         }
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 65247d0..b3e0108 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -151,27 +151,23 @@
             ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task appeared taskId=%d", task.mTaskId);
             final boolean visible = task.isVisible();
             final RunningTaskInfo taskInfo = task.getTaskInfo();
-            mDeferTaskOrgCallbacksConsumer.accept(() -> {
-                try {
-                    mTaskOrganizer.onTaskAppeared(taskInfo, prepareLeash(task, visible,
-                            "TaskOrganizerController.onTaskAppeared"));
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "Exception sending onTaskAppeared callback", e);
-                }
-            });
+            try {
+                mTaskOrganizer.onTaskAppeared(taskInfo, prepareLeash(task, visible,
+                        "TaskOrganizerController.onTaskAppeared"));
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Exception sending onTaskAppeared callback", e);
+            }
         }
 
 
         void onTaskVanished(Task task) {
             ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task vanished taskId=%d", task.mTaskId);
             final RunningTaskInfo taskInfo = task.getTaskInfo();
-            mDeferTaskOrgCallbacksConsumer.accept(() -> {
-                try {
-                    mTaskOrganizer.onTaskVanished(taskInfo);
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "Exception sending onTaskVanished callback", e);
-                }
-            });
+            try {
+                mTaskOrganizer.onTaskVanished(taskInfo);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Exception sending onTaskVanished callback", e);
+            }
         }
 
         void onTaskInfoChanged(Task task, ActivityManager.RunningTaskInfo taskInfo) {
@@ -180,20 +176,18 @@
                 return;
             }
             ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task info changed taskId=%d", task.mTaskId);
-            mDeferTaskOrgCallbacksConsumer.accept(() -> {
-                if (!task.isOrganized()) {
-                    // This is safe to ignore if the task is no longer organized
-                    return;
-                }
-                try {
-                    // Purposely notify of task info change immediately instead of deferring (like
-                    // appear and vanish) to allow info changes (such as new PIP params) to flow
-                    // without waiting.
-                    mTaskOrganizer.onTaskInfoChanged(taskInfo);
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "Exception sending onTaskInfoChanged callback", e);
-                }
-            });
+            if (!task.isOrganized()) {
+                // This is safe to ignore if the task is no longer organized
+                return;
+            }
+            try {
+                // Purposely notify of task info change immediately instead of deferring (like
+                // appear and vanish) to allow info changes (such as new PIP params) to flow
+                // without waiting.
+                mTaskOrganizer.onTaskInfoChanged(taskInfo);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Exception sending onTaskInfoChanged callback", e);
+            }
         }
 
         void onBackPressedOnTaskRoot(Task task) {
@@ -203,17 +197,15 @@
                 // Skip if the task has not yet received taskAppeared().
                 return;
             }
-            mDeferTaskOrgCallbacksConsumer.accept(() -> {
-                if (!task.isOrganized()) {
-                    // This is safe to ignore if the task is no longer organized
-                    return;
-                }
-                try {
-                    mTaskOrganizer.onBackPressedOnTaskRoot(task.getTaskInfo());
-                } catch (Exception e) {
-                    Slog.e(TAG, "Exception sending onBackPressedOnTaskRoot callback", e);
-                }
-            });
+            if (!task.isOrganized()) {
+                // This is safe to ignore if the task is no longer organized
+                return;
+            }
+            try {
+                mTaskOrganizer.onBackPressedOnTaskRoot(task.getTaskInfo());
+            } catch (Exception e) {
+                Slog.e(TAG, "Exception sending onBackPressedOnTaskRoot callback", e);
+            }
         }
     }
 
@@ -258,28 +250,34 @@
             return mOrganizer.prepareLeash(t, t.isVisible(), reason);
         }
 
-        void addTask(Task t) {
-            if (t.mTaskAppearedSent) return;
+        private boolean addTask(Task t) {
+            if (t.mTaskAppearedSent) {
+                return false;
+            }
 
             if (!mOrganizedTasks.contains(t)) {
                 mOrganizedTasks.add(t);
             }
+
             if (t.taskAppearedReady()) {
                 t.mTaskAppearedSent = true;
-                mOrganizer.onTaskAppeared(t);
+                return true;
             }
+            return false;
         }
 
-        void removeTask(Task t) {
+        private boolean removeTask(Task t) {
+            mOrganizedTasks.remove(t);
+            mInterceptBackPressedOnRootTasks.remove(t.mTaskId);
+
             if (t.mTaskAppearedSent) {
                 if (t.getSurfaceControl() != null) {
                     t.migrateToNewSurfaceControl();
                 }
                 t.mTaskAppearedSent = false;
-                mOrganizer.onTaskVanished(t);
+                return true;
             }
-            mOrganizedTasks.remove(t);
-            mInterceptBackPressedOnRootTasks.remove(t.mTaskId);
+            return false;
         }
 
         void dispose() {
@@ -290,8 +288,14 @@
             // possible.
             while (!mOrganizedTasks.isEmpty()) {
                 final Task t = mOrganizedTasks.get(0);
-                if (!t.updateTaskOrganizerState(true /* forceUpdate */)) {
-                    removeTask(t);
+                t.updateTaskOrganizerState(true /* forceUpdate */);
+                if (mOrganizedTasks.contains(t)) {
+                    // updateTaskOrganizerState should remove the task from the list, but still
+                    // check it again to avoid while-loop isn't terminate.
+                    if (removeTask(t)) {
+                        TaskOrganizerController.this.onTaskVanishedInternal(
+                                mOrganizer.mTaskOrganizer, t);
+                    }
                 }
             }
 
@@ -305,6 +309,33 @@
         }
     }
 
+    static class PendingTaskEvent {
+        static final int EVENT_APPEARED = 0;
+        static final int EVENT_VANISHED = 1;
+        static final int EVENT_INFO_CHANGED = 2;
+        static final int EVENT_ROOT_BACK_PRESSED = 3;
+
+        final int mEventType;
+        final Task mTask;
+        final ITaskOrganizer mTaskOrg;
+        boolean mForce;
+
+        PendingTaskEvent(Task task, int event) {
+            this(task, task.mTaskOrganizer, event);
+        }
+
+        PendingTaskEvent(Task task, ITaskOrganizer taskOrg, int eventType) {
+            mTask = task;
+            mTaskOrg = taskOrg;
+            mEventType = eventType;
+        }
+
+        boolean isLifecycleEvent() {
+            return mEventType == EVENT_APPEARED || mEventType == EVENT_VANISHED
+                    || mEventType == EVENT_INFO_CHANGED;
+        }
+    }
+
     private final ActivityTaskManagerService mService;
     private final WindowManagerGlobalLock mGlobalLock;
 
@@ -312,7 +343,8 @@
     private final LinkedList<ITaskOrganizer> mTaskOrganizers = new LinkedList<>();
     private final HashMap<IBinder, TaskOrganizerState> mTaskOrganizerStates = new HashMap<>();
     private final WeakHashMap<Task, RunningTaskInfo> mLastSentTaskInfos = new WeakHashMap<>();
-    private final ArrayList<Task> mPendingTaskInfoChanges = new ArrayList<>();
+    // Pending task events due to layout deferred.
+    private final ArrayList<PendingTaskEvent> mPendingTaskEvents = new ArrayList<>();
     // Set of organized tasks (by taskId) that dispatch back pressed to their organizers
     private final HashSet<Integer> mInterceptBackPressedOnRootTasks = new HashSet();
 
@@ -337,6 +369,12 @@
     public void setDeferTaskOrgCallbacksConsumer(Consumer<Runnable> consumer) {
         mDeferTaskOrgCallbacksConsumer = consumer;
     }
+
+    @VisibleForTesting
+    ArrayList<PendingTaskEvent> getPendingEventList() {
+        return mPendingTaskEvents;
+    }
+
     /**
      * Register a TaskOrganizer to manage tasks as they enter the a supported windowing mode.
      */
@@ -442,16 +480,40 @@
 
     void onTaskAppeared(ITaskOrganizer organizer, Task task) {
         final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
-        state.addTask(task);
+        if (state != null && state.addTask(task)) {
+            PendingTaskEvent pending = getPendingTaskEvent(task, PendingTaskEvent.EVENT_APPEARED);
+            if (pending == null) {
+                pending = new PendingTaskEvent(task, PendingTaskEvent.EVENT_APPEARED);
+                mPendingTaskEvents.add(pending);
+            }
+        }
     }
 
     void onTaskVanished(ITaskOrganizer organizer, Task task) {
         final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
-        if (state != null) {
-            state.removeTask(task);
+        if (state != null && state.removeTask(task)) {
+            onTaskVanishedInternal(organizer, task);
         }
     }
 
+    private void onTaskVanishedInternal(ITaskOrganizer organizer, Task task) {
+        for (int i = mPendingTaskEvents.size() - 1; i >= 0; i--) {
+            PendingTaskEvent entry = mPendingTaskEvents.get(i);
+            if (task.mTaskId == entry.mTask.mTaskId) {
+                // This task is vanished so remove all pending event of it.
+                mPendingTaskEvents.remove(i);
+                if (entry.mEventType == PendingTaskEvent.EVENT_APPEARED) {
+                    // If task appeared callback still pend, ignore this callback too.
+                    return;
+                }
+            }
+        }
+
+        PendingTaskEvent pending =
+                new PendingTaskEvent(task, organizer, PendingTaskEvent.EVENT_VANISHED);
+        mPendingTaskEvents.add(pending);
+    }
+
     @Override
     public void createRootTask(int displayId, int windowingMode, @Nullable IBinder launchCookie) {
         enforceTaskPermission("createRootTask()");
@@ -518,30 +580,76 @@
         }
     }
 
-    void dispatchPendingTaskInfoChanges() {
-        if (mService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred()) {
+    void dispatchPendingEvents() {
+        if (mService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred()
+                || mPendingTaskEvents.isEmpty()) {
             return;
         }
-        for (int i = 0, n = mPendingTaskInfoChanges.size(); i < n; ++i) {
-            dispatchTaskInfoChanged(mPendingTaskInfoChanges.get(i), false /* force */);
+
+        for (int i = 0, n = mPendingTaskEvents.size(); i < n; i++) {
+            PendingTaskEvent event = mPendingTaskEvents.get(i);
+            final Task task = event.mTask;
+            final TaskOrganizerState state;
+            switch (event.mEventType) {
+                case PendingTaskEvent.EVENT_APPEARED:
+                    state = mTaskOrganizerStates.get(event.mTaskOrg.asBinder());
+                    if (state != null && task.taskAppearedReady()) {
+                        state.mOrganizer.onTaskAppeared(task);
+                    }
+                    break;
+                case PendingTaskEvent.EVENT_VANISHED:
+                    state = mTaskOrganizerStates.get(event.mTaskOrg.asBinder());
+                    if (state != null) {
+                        state.mOrganizer.onTaskVanished(task);
+                    }
+                    break;
+                case PendingTaskEvent.EVENT_INFO_CHANGED:
+                    dispatchTaskInfoChanged(event.mTask, event.mForce);
+                    break;
+                case PendingTaskEvent.EVENT_ROOT_BACK_PRESSED:
+                    state = mTaskOrganizerStates.get(event.mTaskOrg.asBinder());
+                    if (state != null) {
+                        state.mOrganizer.onBackPressedOnTaskRoot(task);
+                    }
+                    break;
+            }
         }
-        mPendingTaskInfoChanges.clear();
+        mPendingTaskEvents.clear();
     }
 
-    void dispatchTaskInfoChanged(Task task, boolean force) {
-        if (!force && mService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred()) {
-            // Defer task info reporting while layout is deferred. This is because layout defer
-            // blocks tend to do lots of re-ordering which can mess up animations in receivers.
-            mPendingTaskInfoChanges.remove(task);
-            mPendingTaskInfoChanges.add(task);
+    void onTaskInfoChanged(Task task, boolean force) {
+        if (!task.mTaskAppearedSent) {
+            // Skip if task still not appeared.
             return;
         }
+
+        // Defer task info reporting while layout is deferred. This is because layout defer
+        // blocks tend to do lots of re-ordering which can mess up animations in receivers.
+        PendingTaskEvent pending = getPendingLifecycleTaskEvent(task);
+        if (pending == null) {
+            pending = new PendingTaskEvent(task, PendingTaskEvent.EVENT_INFO_CHANGED);
+        } else {
+            if (pending.mEventType != PendingTaskEvent.EVENT_INFO_CHANGED) {
+                // If queued event is appeared, it means task still not appeared so ignore
+                // this info changed. If queued event is vanished, it means task should
+                // will vanished early so do not need this info changed.
+                return;
+            }
+            // Remove and add for re-ordering.
+            mPendingTaskEvents.remove(pending);
+        }
+        pending.mForce = force;
+        mPendingTaskEvents.add(pending);
+    }
+
+    private void dispatchTaskInfoChanged(Task task, boolean force) {
         RunningTaskInfo lastInfo = mLastSentTaskInfos.get(task);
         if (mTmpTaskInfo == null) {
             mTmpTaskInfo = new RunningTaskInfo();
         }
         mTmpTaskInfo.configuration.unset();
         task.fillTaskInfo(mTmpTaskInfo);
+
         boolean changed = !mTmpTaskInfo.equalsForTaskOrganizer(lastInfo);
         if (!changed) {
             int cfgChanges = mTmpTaskInfo.configuration.diff(lastInfo.configuration);
@@ -705,11 +813,48 @@
             return false;
         }
 
-        final TaskOrganizerState state = mTaskOrganizerStates.get(task.mTaskOrganizer.asBinder());
-        state.mOrganizer.onBackPressedOnTaskRoot(task);
+        PendingTaskEvent pendingVanished =
+                getPendingTaskEvent(task, PendingTaskEvent.EVENT_VANISHED);
+        if (pendingVanished != null) {
+            // This task will vanish before this callback so just ignore.
+            return false;
+        }
+
+        PendingTaskEvent pending = getPendingTaskEvent(
+                task, PendingTaskEvent.EVENT_ROOT_BACK_PRESSED);
+        if (pending == null) {
+            pending = new PendingTaskEvent(task, PendingTaskEvent.EVENT_ROOT_BACK_PRESSED);
+        } else {
+            // Pending already exist, remove and add for re-ordering.
+            mPendingTaskEvents.remove(pending);
+        }
+        mPendingTaskEvents.add(pending);
         return true;
     }
 
+    @Nullable
+    private PendingTaskEvent getPendingTaskEvent(Task task, int type) {
+        for (int i = mPendingTaskEvents.size() - 1; i >= 0; i--) {
+            PendingTaskEvent entry = mPendingTaskEvents.get(i);
+            if (task.mTaskId == entry.mTask.mTaskId && type == entry.mEventType) {
+                return entry;
+            }
+        }
+        return null;
+    }
+
+    @VisibleForTesting
+    @Nullable
+    PendingTaskEvent getPendingLifecycleTaskEvent(Task task) {
+        for (int i = mPendingTaskEvents.size() - 1; i >= 0; i--) {
+            PendingTaskEvent entry = mPendingTaskEvents.get(i);
+            if (task.mTaskId == entry.mTask.mTaskId && entry.isLifecycleEvent()) {
+                return entry;
+            }
+        }
+        return null;
+    }
+
     public void dump(PrintWriter pw, String prefix) {
         final String innerPrefix = prefix + "  ";
         pw.print(prefix); pw.println("TaskOrganizerController:");
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index ed90cc75..513fa70 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -370,14 +370,26 @@
         SurfaceControl[] excludeLayers;
         final WindowState imeWindow = task.getDisplayContent().mInputMethodWindow;
         // Exclude IME window snapshot when IME isn't proper to attach to app.
-        if (imeWindow != null && imeWindow.getSurfaceControl() != null
-                && !task.getDisplayContent().isImeAttachedToApp()) {
-            excludeLayers = new SurfaceControl[1];
+        final boolean excludeIme = imeWindow != null && imeWindow.getSurfaceControl() != null
+                && !task.getDisplayContent().isImeAttachedToApp();
+        final WindowState navWindow =
+                task.getDisplayContent().getDisplayPolicy().getNavigationBar();
+        // If config_attachNavBarToAppDuringTransition is true, the nav bar will be reparent to the
+        // the swiped app when entering recent app, therefore the task will contain the navigation
+        // bar and we should exclude it from snapshot.
+        final boolean excludeNavBar = navWindow != null;
+        if (excludeIme && excludeNavBar) {
+            excludeLayers = new SurfaceControl[2];
             excludeLayers[0] = imeWindow.getSurfaceControl();
+            excludeLayers[1] = navWindow.getSurfaceControl();
+        } else if (excludeIme || excludeNavBar) {
+            excludeLayers = new SurfaceControl[1];
+            excludeLayers[0] =
+                    excludeIme ? imeWindow.getSurfaceControl() : navWindow.getSurfaceControl();
         } else {
             excludeLayers = new SurfaceControl[0];
-            builder.setHasImeSurface(imeWindow != null && imeWindow.isDrawn());
         }
+        builder.setHasImeSurface(!excludeIme && imeWindow != null && imeWindow.isDrawn());
         final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
                 SurfaceControl.captureLayersExcluding(
                         task.getSurfaceControl(), mTmpRect, scaleFraction,
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index b37e3c4..46aea23 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -50,6 +50,7 @@
 import android.view.SurfaceControl;
 import android.view.WindowManager;
 import android.view.animation.Animation;
+import android.window.IRemoteTransition;
 import android.window.TransitionInfo;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -101,6 +102,7 @@
     private @WindowManager.TransitionFlags int mFlags;
     private final TransitionController mController;
     private final BLASTSyncEngine mSyncEngine;
+    private IRemoteTransition mRemoteTransition = null;
 
     /**
      * This is a leash to put animating surfaces into flatly without clipping/ordering issues. It
@@ -235,8 +237,14 @@
             if (target.getParent() != null) {
                 // Ensure surfaceControls are re-parented back into the hierarchy.
                 t.reparent(target.getSurfaceControl(), target.getParent().getSurfaceControl());
+                t.setLayer(target.getSurfaceControl(), target.getLastLayer());
+                // TODO(shell-transitions): Once all remotables have been moved, see if there is
+                //                          a more appropriate place to do the following. This may
+                //                          involve passing an SF transaction from shell on finish.
                 target.getRelativePosition(tmpPos);
                 t.setPosition(target.getSurfaceControl(), tmpPos.x, tmpPos.y);
+                t.setCornerRadius(target.getSurfaceControl(), 0);
+                t.setShadowRadius(target.getSurfaceControl(), 0);
                 displays.add(target.getDisplayContent());
             }
         }
@@ -283,6 +291,14 @@
         mSyncEngine.abort(mSyncId);
     }
 
+    void setRemoteTransition(IRemoteTransition remoteTransition) {
+        mRemoteTransition = remoteTransition;
+    }
+
+    IRemoteTransition getRemoteTransition() {
+        return mRemoteTransition;
+    }
+
     @Override
     public void onTransactionReady(int syncId, SurfaceControl.Transaction transaction) {
         if (syncId != mSyncId) {
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 0fe0afa..5f46ffe 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -26,7 +26,9 @@
 import android.os.RemoteException;
 import android.util.Slog;
 import android.view.WindowManager;
+import android.window.IRemoteTransition;
 import android.window.ITransitionPlayer;
+import android.window.TransitionRequestInfo;
 
 import com.android.internal.protolog.ProtoLogGroup;
 import com.android.internal.protolog.common.ProtoLog;
@@ -140,7 +142,7 @@
     }
 
     /**
-     * @see #requestTransitionIfNeeded(int, int)
+     * @see #requestTransitionIfNeeded(int, int, WindowContainer, IRemoteTransition)
      */
     @Nullable
     Transition requestTransitionIfNeeded(@WindowManager.TransitionType int type,
@@ -148,9 +150,19 @@
         return requestTransitionIfNeeded(type, 0 /* flags */, trigger);
     }
 
+    /**
+     * @see #requestTransitionIfNeeded(int, int, WindowContainer, IRemoteTransition)
+     */
+    @Nullable
+    Transition requestTransitionIfNeeded(@WindowManager.TransitionType int type,
+            @WindowManager.TransitionFlags int flags, @Nullable WindowContainer trigger) {
+        return requestTransitionIfNeeded(type, flags, trigger, null /* remote */);
+    }
+
     private static boolean isExistenceType(@WindowManager.TransitionType int type) {
         return type == TRANSIT_OPEN || type == TRANSIT_CLOSE;
     }
+
     /**
      * If a transition isn't requested yet, creates one and asks the TransitionPlayer (Shell) to
      * start it. Collection can start immediately.
@@ -159,7 +171,8 @@
      */
     @Nullable
     Transition requestTransitionIfNeeded(@WindowManager.TransitionType int type,
-            @WindowManager.TransitionFlags int flags, @Nullable WindowContainer trigger) {
+            @WindowManager.TransitionFlags int flags, @Nullable WindowContainer trigger,
+            @Nullable IRemoteTransition remoteTransition) {
         if (mTransitionPlayer == null) {
             return null;
         }
@@ -169,7 +182,7 @@
             mCollectingTransition.setReady(false);
         } else {
             newTransition = requestStartTransition(createTransition(type, flags),
-                    trigger != null ? trigger.asTask() : null);
+                    trigger != null ? trigger.asTask() : null, remoteTransition);
         }
         if (trigger != null) {
             if (isExistenceType(type)) {
@@ -183,7 +196,8 @@
 
     /** Asks the transition player (shell) to start a created but not yet started transition. */
     @NonNull
-    Transition requestStartTransition(@NonNull Transition transition, @Nullable Task startTask) {
+    Transition requestStartTransition(@NonNull Transition transition, @Nullable Task startTask,
+            @Nullable IRemoteTransition remoteTransition) {
         try {
             ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
                     "Requesting StartTransition: %s", transition);
@@ -192,7 +206,8 @@
                 info = new ActivityManager.RunningTaskInfo();
                 startTask.fillTaskInfo(info);
             }
-            mTransitionPlayer.requestStartTransition(transition.mType, transition, info);
+            mTransitionPlayer.requestStartTransition(transition, new TransitionRequestInfo(
+                    transition.mType, info, remoteTransition));
         } catch (RemoteException e) {
             Slog.e(TAG, "Error requesting transition", e);
             transition.start();
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index c4eb635..52ed278 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -222,6 +222,7 @@
 
         mService.destroyPreservedSurfaceLocked();
 
+        mService.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         executeAfterPrepareSurfacesRunnables();
 
         if (DEBUG_WINDOW_TRACE) {
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index be1f7e1..1509ff6 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -264,11 +264,18 @@
             for (int i = 0, n = hops.size(); i < n; ++i) {
                 final WindowContainerTransaction.HierarchyOp hop = hops.get(i);
                 switch (hop.getType()) {
-                    case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT:
-                        final Task task = WindowContainer.fromBinder(hop.getContainer()).asTask();
+                    case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: {
+                        final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
+                        final Task task = wc != null ? wc.asTask() : null;
+                        if (task != null) {
                             task.getDisplayArea().setLaunchRootTask(task,
                                     hop.getWindowingModes(), hop.getActivityTypes());
+                        } else {
+                            throw new IllegalArgumentException(
+                                    "Cannot set non-task as launch root: " + wc);
+                        }
                         break;
+                    }
                     case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT:
                         effects |= reparentChildrenTasksHierarchyOp(hop, transition, syncId);
                         break;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 124e120..13b9765 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -213,6 +213,7 @@
 import android.os.WorkSource;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.DisplayMetrics;
 import android.util.MergedConfiguration;
@@ -645,9 +646,14 @@
     boolean mSeamlesslyRotated = false;
 
     /**
-     * Indicates if this window is behind IME. Only windows behind IME can get insets from IME.
+     * The insets state of sources provided by windows above the current window.
      */
-    boolean mBehindIme = false;
+    InsetsState mAboveInsetsState = new InsetsState();
+
+    /**
+     * The insets sources provided by this window.
+     */
+    ArrayMap<Integer, InsetsSource> mProvidedInsetsSources = new ArrayMap<>();
 
     /**
      * Surface insets from the previous call to relayout(), used to track
@@ -2097,7 +2103,7 @@
         return getDisplayContent().getBounds().equals(getBounds());
     }
 
-    private boolean matchesRootDisplayAreaBounds() {
+    boolean matchesRootDisplayAreaBounds() {
         RootDisplayArea root = getRootDisplayArea();
         if (root == null || root == getDisplayContent()) {
             return matchesDisplayBounds();
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 13c6752..dc15b07 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -161,7 +161,7 @@
     jmethodID size;
 } gSparseArrayClassInfo;
 
-struct InputSensorInfoOffsets {
+static struct InputSensorInfoOffsets {
     jclass clazz;
     // fields
     jfieldID name;
diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp
index 4e1a234..a5311f3 100644
--- a/services/core/jni/com_android_server_tv_TvInputHal.cpp
+++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp
@@ -261,7 +261,7 @@
 
     void onDeviceAvailable(const TvInputDeviceInfo& info);
     void onDeviceUnavailable(int deviceId);
-    void onStreamConfigurationsChanged(int deviceId);
+    void onStreamConfigurationsChanged(int deviceId, int cableConnectionStatus);
     void onCaptured(int deviceId, int streamId, uint32_t seq, bool succeeded);
 
 private:
@@ -519,7 +519,7 @@
             deviceId);
 }
 
-void JTvInputHal::onStreamConfigurationsChanged(int deviceId) {
+void JTvInputHal::onStreamConfigurationsChanged(int deviceId, int cableConnectionStatus) {
     {
         Mutex::Autolock autoLock(&mLock);
         KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
@@ -529,10 +529,8 @@
         connections.clear();
     }
     JNIEnv* env = AndroidRuntime::getJNIEnv();
-    env->CallVoidMethod(
-            mThiz,
-            gTvInputHalClassInfo.streamConfigsChanged,
-            deviceId);
+    env->CallVoidMethod(mThiz, gTvInputHalClassInfo.streamConfigsChanged, deviceId,
+                        cableConnectionStatus);
 }
 
 void JTvInputHal::onCaptured(int deviceId, int streamId, uint32_t seq, bool succeeded) {
@@ -572,7 +570,8 @@
             mHal->onDeviceUnavailable(mEvent.deviceInfo.deviceId);
         } break;
         case TvInputEventType::STREAM_CONFIGURATIONS_CHANGED: {
-            mHal->onStreamConfigurationsChanged(mEvent.deviceInfo.deviceId);
+            int cableConnectionStatus = static_cast<int>(mEvent.deviceInfo.cableConnectionStatus);
+            mHal->onStreamConfigurationsChanged(mEvent.deviceInfo.deviceId, cableConnectionStatus);
         } break;
         default:
             ALOGE("Unrecognizable event");
@@ -688,9 +687,8 @@
             "deviceAvailableFromNative", "(Landroid/media/tv/TvInputHardwareInfo;)V");
     GET_METHOD_ID(
             gTvInputHalClassInfo.deviceUnavailable, clazz, "deviceUnavailableFromNative", "(I)V");
-    GET_METHOD_ID(
-            gTvInputHalClassInfo.streamConfigsChanged, clazz,
-            "streamConfigsChangedFromNative", "(I)V");
+    GET_METHOD_ID(gTvInputHalClassInfo.streamConfigsChanged, clazz,
+                  "streamConfigsChangedFromNative", "(II)V");
     GET_METHOD_ID(
             gTvInputHalClassInfo.firstFrameCaptured, clazz,
             "firstFrameCapturedFromNative", "(II)V");
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 737bf95..7df9016 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3383,6 +3383,7 @@
 
         final CallerIdentity caller = getCallerIdentity();
         Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
+        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_REMOVE_ACTIVE_ADMIN);
         enforceUserUnlocked(userHandle);
 
         synchronized (getLockObject()) {
@@ -5143,6 +5144,7 @@
         }
         final CallerIdentity caller = getCallerIdentity(admin, callerPackage);
         Preconditions.checkCallAuthorization(canManageCaCerts(caller));
+        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_INSTALL_CA_CERT);
 
         final String alias = mInjector.binderWithCleanCallingIdentity(() -> {
             String installedAlias = mCertificateMonitor.installCaCert(
@@ -5174,6 +5176,7 @@
         }
         final CallerIdentity caller = getCallerIdentity(admin, callerPackage);
         Preconditions.checkCallAuthorization(canManageCaCerts(caller));
+        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_UNINSTALL_CA_CERT);
 
         mInjector.binderWithCleanCallingIdentity(() -> {
             mCertificateMonitor.uninstallCaCerts(caller.getUserHandle(), aliases);
@@ -5203,6 +5206,7 @@
         Preconditions.checkCallAuthorization((caller.hasAdminComponent()
                 && (isProfileOwner(caller) || isDeviceOwner(caller)))
                 || (caller.hasPackage() && (isCallerDelegate || isCredentialManagementApp)));
+        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_INSTALL_KEY_PAIR);
 
         final long id = mInjector.binderClearCallingIdentity();
         try {
@@ -5260,6 +5264,7 @@
         Preconditions.checkCallAuthorization((caller.hasAdminComponent()
                 && (isProfileOwner(caller) || isDeviceOwner(caller)))
                 || (caller.hasPackage() && (isCallerDelegate || isCredentialManagementApp)));
+        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_REMOVE_KEY_PAIR);
 
         final long id = Binder.clearCallingIdentity();
         try {
@@ -6157,6 +6162,7 @@
 
         final CallerIdentity caller = getCallerIdentity(who);
         Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
+        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_ALWAYS_ON_VPN_PACKAGE);
 
         final int userId = caller.getUserId();
         mInjector.binderWithCleanCallingIdentity(() -> {
@@ -6500,6 +6506,8 @@
         CallerIdentity caller = getCallerIdentity(who);
         Preconditions.checkCallAuthorization(isDeviceOwner(caller)
                 || isProfileOwnerOfOrganizationOwnedDevice(caller));
+        checkCanExecuteOrThrowUnsafe(DevicePolicyManager
+                .OPERATION_SET_FACTORY_RESET_PROTECTION_POLICY);
 
         final int frpManagementAgentUid = getFrpManagementAgentUidOrThrow();
         synchronized (getLockObject()) {
@@ -7397,6 +7405,7 @@
         final CallerIdentity caller = getCallerIdentity(who);
         Preconditions.checkCallAuthorization(isDeviceOwner(caller));
         checkAllUsersAreAffiliatedWithDevice();
+        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_REQUEST_BUGREPORT);
 
         if (mBugreportCollectionManager.requestBugreport()) {
             DevicePolicyEventLogger
@@ -7506,6 +7515,7 @@
         if (parent) {
             Preconditions.checkCallAuthorization(isProfileOwnerOfOrganizationOwnedDevice(caller));
         }
+        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_CAMERA_DISABLED);
 
         final int userHandle = caller.getUserId();
         synchronized (getLockObject()) {
@@ -8640,11 +8650,6 @@
         if (isCallerProfileOwnerOrDelegate && isProfileOwnerOfOrganizationOwnedDevice(userId)) {
             return true;
         }
-        //TODO(b/130844684): Temporarily allow profile owner on non-organization-owned devices
-        //to read device identifiers.
-        if (isCallerProfileOwnerOrDelegate) {
-            return true;
-        }
 
         return false;
     }
@@ -9256,6 +9261,7 @@
         Objects.requireNonNull(who, "ComponentName is null");
         final CallerIdentity caller = getCallerIdentity(who);
         Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
+        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_RESTRICTIONS_PROVIDER);
 
         synchronized (getLockObject()) {
             int userHandle = caller.getUserId();
@@ -11431,6 +11437,7 @@
         Objects.requireNonNull(who, "ComponentName is null");
         final CallerIdentity caller = getCallerIdentity(who);
         Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
+        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_MASTER_VOLUME_MUTED);
 
         synchronized (getLockObject()) {
             setUserRestriction(who, UserManager.DISALLOW_UNMUTE_DEVICE, on, /* parent */ false);
@@ -12407,6 +12414,7 @@
         Preconditions.checkCallAuthorization((caller.hasAdminComponent()
                 && (isProfileOwner(caller) || isDeviceOwner(caller)))
                 || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_PERMISSION_GRANT)));
+        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_PERMISSION_POLICY);
 
         synchronized (getLockObject()) {
             DevicePolicyData userPolicy = getUserData(caller.getUserId());
@@ -12442,6 +12450,7 @@
         Preconditions.checkCallAuthorization((caller.hasAdminComponent()
                 && (isProfileOwner(caller) || isDeviceOwner(caller)))
                 || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_PERMISSION_GRANT)));
+        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_PERMISSION_GRANT_STATE);
 
         synchronized (getLockObject()) {
             long ident = mInjector.binderClearCallingIdentity();
@@ -14418,6 +14427,7 @@
 
         final CallerIdentity caller = getCallerIdentity(admin);
         Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
+        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_CLEAR_APPLICATION_USER_DATA);
 
         long ident = mInjector.binderClearCallingIdentity();
         try {
@@ -14449,6 +14459,7 @@
         Objects.requireNonNull(admin, "ComponentName is null");
         final CallerIdentity caller = getCallerIdentity(admin);
         Preconditions.checkCallAuthorization(isDeviceOwner(caller));
+        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_LOGOUT_ENABLED);
 
         synchronized (getLockObject()) {
             ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
@@ -14816,6 +14827,8 @@
         Objects.requireNonNull(who, "ComponentName is null");
         final CallerIdentity caller = getCallerIdentity(who);
         Preconditions.checkCallAuthorization(isDeviceOwner(caller));
+        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_OVERRIDE_APNS_ENABLED);
+
         setOverrideApnsEnabledUnchecked(enabled);
     }
 
@@ -14917,6 +14930,7 @@
         Objects.requireNonNull(who, "ComponentName is null");
         final CallerIdentity caller = getCallerIdentity(who);
         Preconditions.checkCallAuthorization(isDeviceOwner(caller));
+        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_GLOBAL_PRIVATE_DNS);
 
         switch (mode) {
             case PRIVATE_DNS_MODE_OPPORTUNISTIC:
@@ -14989,6 +15003,7 @@
         final CallerIdentity caller = getCallerIdentity(admin);
         Preconditions.checkCallAuthorization(isDeviceOwner(caller)
                 || isProfileOwnerOfOrganizationOwnedDevice(caller));
+        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_INSTALL_SYSTEM_UPDATE);
 
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.INSTALL_SYSTEM_UPDATE)
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 94df185..57b3e8d 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -160,7 +160,7 @@
 import com.android.server.pm.dex.SystemServerDexLoadReporter;
 import com.android.server.policy.PermissionPolicyService;
 import com.android.server.policy.PhoneWindowManager;
-import com.android.server.policy.role.LegacyRoleResolutionPolicy;
+import com.android.server.policy.role.LegacyRoleStateProviderImpl;
 import com.android.server.power.PowerManagerService;
 import com.android.server.power.ShutdownThread;
 import com.android.server.power.ThermalManagerService;
@@ -2021,7 +2021,7 @@
             // Grants default permissions and defines roles
             t.traceBegin("StartRoleManagerService");
             mSystemServiceManager.startService(new RoleManagerService(
-                    mSystemContext, new LegacyRoleResolutionPolicy(mSystemContext)));
+                    mSystemContext, new LegacyRoleStateProviderImpl(mSystemContext)));
             t.traceEnd();
 
             // We need to always start this service, regardless of whether the
diff --git a/services/people/java/com/android/server/people/data/AbstractProtoDiskReadWriter.java b/services/people/java/com/android/server/people/data/AbstractProtoDiskReadWriter.java
index e4daddc..0a85f7f 100644
--- a/services/people/java/com/android/server/people/data/AbstractProtoDiskReadWriter.java
+++ b/services/people/java/com/android/server/people/data/AbstractProtoDiskReadWriter.java
@@ -85,8 +85,10 @@
     }
 
     @WorkerThread
-    synchronized void delete(@NonNull String fileName) {
-        mScheduledFileDataMap.remove(fileName);
+    void delete(@NonNull String fileName) {
+        synchronized (this) {
+            mScheduledFileDataMap.remove(fileName);
+        }
         final File file = getFile(fileName);
         if (!file.exists()) {
             return;
@@ -136,28 +138,6 @@
     }
 
     /**
-     * Reads all files in directory and returns a map with file names as keys and parsed file
-     * contents as values.
-     */
-    @WorkerThread
-    @Nullable
-    Map<String, T> readAll() {
-        File[] files = mRootDir.listFiles(File::isFile);
-        if (files == null) {
-            return null;
-        }
-
-        Map<String, T> results = new ArrayMap<>();
-        for (File file : files) {
-            T result = parseFile(file);
-            if (result != null) {
-                results.put(file.getName(), result);
-            }
-        }
-        return results;
-    }
-
-    /**
      * Schedules the specified data to be flushed to a file in the future. Subsequent
      * calls for the same file before the flush occurs will replace the previous data but will not
      * reset when the flush will occur. All unique files will be flushed at the same time.
diff --git a/services/people/java/com/android/server/people/data/ConversationStore.java b/services/people/java/com/android/server/people/data/ConversationStore.java
index 28e3d4b..6faeb80 100644
--- a/services/people/java/com/android/server/people/data/ConversationStore.java
+++ b/services/people/java/com/android/server/people/data/ConversationStore.java
@@ -90,7 +90,7 @@
      * after the device powers on and the user has been unlocked.
      */
     @WorkerThread
-    synchronized void loadConversationsFromDisk() {
+    void loadConversationsFromDisk() {
         ConversationInfosProtoDiskReadWriter conversationInfosProtoDiskReadWriter =
                 getConversationInfosProtoDiskReadWriter();
         if (conversationInfosProtoDiskReadWriter == null) {
@@ -111,54 +111,64 @@
      * powering off.
      */
     @MainThread
-    synchronized void saveConversationsToDisk() {
+    void saveConversationsToDisk() {
         ConversationInfosProtoDiskReadWriter conversationInfosProtoDiskReadWriter =
                 getConversationInfosProtoDiskReadWriter();
         if (conversationInfosProtoDiskReadWriter != null) {
-            conversationInfosProtoDiskReadWriter.saveConversationsImmediately(
-                    new ArrayList<>(mConversationInfoMap.values()));
+            List<ConversationInfo> conversations;
+            synchronized (this) {
+                conversations = new ArrayList<>(mConversationInfoMap.values());
+            }
+            conversationInfosProtoDiskReadWriter.saveConversationsImmediately(conversations);
         }
     }
 
     @MainThread
-    synchronized void addOrUpdate(@NonNull ConversationInfo conversationInfo) {
+    void addOrUpdate(@NonNull ConversationInfo conversationInfo) {
         updateConversationsInMemory(conversationInfo);
         scheduleUpdateConversationsOnDisk();
     }
 
     @MainThread
     @Nullable
-    synchronized ConversationInfo deleteConversation(@NonNull String shortcutId) {
-        ConversationInfo conversationInfo = mConversationInfoMap.remove(shortcutId);
-        if (conversationInfo == null) {
-            return null;
-        }
+    ConversationInfo deleteConversation(@NonNull String shortcutId) {
+        ConversationInfo conversationInfo;
+        synchronized (this) {
+            conversationInfo = mConversationInfoMap.remove(shortcutId);
+            if (conversationInfo == null) {
+                return null;
+            }
 
-        LocusId locusId = conversationInfo.getLocusId();
-        if (locusId != null) {
-            mLocusIdToShortcutIdMap.remove(locusId);
-        }
+            LocusId locusId = conversationInfo.getLocusId();
+            if (locusId != null) {
+                mLocusIdToShortcutIdMap.remove(locusId);
+            }
 
-        Uri contactUri = conversationInfo.getContactUri();
-        if (contactUri != null) {
-            mContactUriToShortcutIdMap.remove(contactUri);
-        }
+            Uri contactUri = conversationInfo.getContactUri();
+            if (contactUri != null) {
+                mContactUriToShortcutIdMap.remove(contactUri);
+            }
 
-        String phoneNumber = conversationInfo.getContactPhoneNumber();
-        if (phoneNumber != null) {
-            mPhoneNumberToShortcutIdMap.remove(phoneNumber);
-        }
+            String phoneNumber = conversationInfo.getContactPhoneNumber();
+            if (phoneNumber != null) {
+                mPhoneNumberToShortcutIdMap.remove(phoneNumber);
+            }
 
-        String notifChannelId = conversationInfo.getNotificationChannelId();
-        if (notifChannelId != null) {
-            mNotifChannelIdToShortcutIdMap.remove(notifChannelId);
+            String notifChannelId = conversationInfo.getNotificationChannelId();
+            if (notifChannelId != null) {
+                mNotifChannelIdToShortcutIdMap.remove(notifChannelId);
+            }
         }
         scheduleUpdateConversationsOnDisk();
         return conversationInfo;
     }
 
-    synchronized void forAllConversations(@NonNull Consumer<ConversationInfo> consumer) {
-        for (ConversationInfo ci : mConversationInfoMap.values()) {
+    void forAllConversations(@NonNull Consumer<ConversationInfo> consumer) {
+        List<ConversationInfo> conversations;
+        synchronized (this) {
+            conversations = new ArrayList<>(mConversationInfoMap.values());
+        }
+        for (ConversationInfo ci : conversations) {
             consumer.accept(ci);
         }
     }
@@ -184,16 +194,19 @@
     }
 
     @Nullable
-    ConversationInfo getConversationByNotificationChannelId(@NonNull String notifChannelId) {
+    synchronized ConversationInfo getConversationByNotificationChannelId(
+            @NonNull String notifChannelId) {
         return getConversation(mNotifChannelIdToShortcutIdMap.get(notifChannelId));
     }
 
-    synchronized void onDestroy() {
-        mConversationInfoMap.clear();
-        mContactUriToShortcutIdMap.clear();
-        mLocusIdToShortcutIdMap.clear();
-        mNotifChannelIdToShortcutIdMap.clear();
-        mPhoneNumberToShortcutIdMap.clear();
+    void onDestroy() {
+        synchronized (this) {
+            mConversationInfoMap.clear();
+            mContactUriToShortcutIdMap.clear();
+            mLocusIdToShortcutIdMap.clear();
+            mNotifChannelIdToShortcutIdMap.clear();
+            mPhoneNumberToShortcutIdMap.clear();
+        }
         ConversationInfosProtoDiskReadWriter writer = getConversationInfosProtoDiskReadWriter();
         if (writer != null) {
             writer.deleteConversationsFile();
@@ -201,22 +214,21 @@
     }
 
     @Nullable
-    synchronized byte[] getBackupPayload() {
+    byte[] getBackupPayload() {
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         DataOutputStream conversationInfosOut = new DataOutputStream(baos);
-        for (ConversationInfo conversationInfo : mConversationInfoMap.values()) {
+        forAllConversations(conversationInfo -> {
             byte[] backupPayload = conversationInfo.getBackupPayload();
             if (backupPayload == null) {
-                continue;
+                return;
             }
             try {
                 conversationInfosOut.writeInt(backupPayload.length);
                 conversationInfosOut.write(backupPayload);
             } catch (IOException e) {
                 Slog.e(TAG, "Failed to write conversation info to backup payload.", e);
-                return null;
             }
-        }
+        });
         try {
             conversationInfosOut.writeInt(CONVERSATION_INFOS_END_TOKEN);
         } catch (IOException e) {
@@ -226,7 +238,7 @@
         return baos.toByteArray();
     }
 
-    synchronized void restore(@NonNull byte[] payload) {
+    void restore(@NonNull byte[] payload) {
         DataInputStream in = new DataInputStream(new ByteArrayInputStream(payload));
         try {
             for (int conversationInfoSize = in.readInt();
@@ -245,7 +257,6 @@
         }
     }
 
-    @MainThread
     private synchronized void updateConversationsInMemory(
             @NonNull ConversationInfo conversationInfo) {
         mConversationInfoMap.put(conversationInfo.getShortcutId(), conversationInfo);
@@ -273,12 +284,15 @@
 
     /** Schedules a dump of all conversations onto disk, overwriting existing values. */
     @MainThread
-    private synchronized void scheduleUpdateConversationsOnDisk() {
+    private void scheduleUpdateConversationsOnDisk() {
         ConversationInfosProtoDiskReadWriter conversationInfosProtoDiskReadWriter =
                 getConversationInfosProtoDiskReadWriter();
         if (conversationInfosProtoDiskReadWriter != null) {
-            conversationInfosProtoDiskReadWriter.scheduleConversationsSave(
-                    new ArrayList<>(mConversationInfoMap.values()));
+            List<ConversationInfo> conversations;
+            synchronized (this) {
+                conversations = new ArrayList<>(mConversationInfoMap.values());
+            }
+            conversationInfosProtoDiskReadWriter.scheduleConversationsSave(conversations);
         }
     }
 
diff --git a/services/searchui/OWNERS b/services/searchui/OWNERS
new file mode 100644
index 0000000..92835c2
--- /dev/null
+++ b/services/searchui/OWNERS
@@ -0,0 +1,2 @@
+hyunyoungs@google.com
+sfufa@google.com
diff --git a/services/tests/mockingservicestests/AndroidManifest.xml b/services/tests/mockingservicestests/AndroidManifest.xml
index fbde1d2..e4b650c 100644
--- a/services/tests/mockingservicestests/AndroidManifest.xml
+++ b/services/tests/mockingservicestests/AndroidManifest.xml
@@ -21,11 +21,13 @@
 
     <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE"/>
     <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"/>
+    <uses-permission android:name="android.permission.READ_DEVICE_CONFIG"/>
     <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
     <uses-permission android:name="android.permission.HARDWARE_TEST"/>
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
     <uses-permission android:name="android.permission.MANAGE_APPOPS"/>
     <uses-permission android:name="android.permission.MONITOR_DEVICE_CONFIG_ACCESS"/>
+    <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG"/>
 
     <!-- needed by MasterClearReceiverTest to display a system dialog -->
     <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"/>
diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
index f4c6918..e99113d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
@@ -351,6 +351,7 @@
         // them after each test, otherwise, subsequent tests will fail.
         LocalServices.removeServiceForTest(AppStateTracker.class);
         LocalServices.removeServiceForTest(DeviceIdleInternal.class);
+        LocalServices.removeServiceForTest(PowerAllowlistInternal.class);
     }
 
     @Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java
new file mode 100644
index 0000000..3710396
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/am/CacheOomRankerTest.java
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManagerInternal;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Process;
+import android.provider.DeviceConfig;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.server.LocalServices;
+import com.android.server.ServiceThread;
+import com.android.server.appop.AppOpsService;
+import com.android.server.testables.TestableDeviceConfig;
+import com.android.server.wm.ActivityTaskManagerService;
+
+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.MockitoJUnitRunner;
+
+import java.io.File;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests for {@link CachedAppOptimizer}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksMockingServicesTests:CacheOomRankerTest
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class CacheOomRankerTest {
+
+    @Mock
+    private AppOpsService mAppOpsService;
+    private Handler mHandler;
+    private ActivityManagerService mAms;
+
+    @Mock
+    private PackageManagerInternal mPackageManagerInt;
+
+    @Rule
+    public final TestableDeviceConfig.TestableDeviceConfigRule
+            mDeviceConfigRule = new TestableDeviceConfig.TestableDeviceConfigRule();
+    @Rule
+    public final ApplicationExitInfoTest.ServiceThreadRule
+            mServiceThreadRule = new ApplicationExitInfoTest.ServiceThreadRule();
+
+    private int mNextPid = 10000;
+    private int mNextUid = 30000;
+    private int mNextPackageUid = 40000;
+    private int mNextPackageName = 1;
+
+    private TestExecutor mExecutor = new TestExecutor();
+    private CacheOomRanker mCacheOomRanker = new CacheOomRanker();
+
+    @Before
+    public void setUp() {
+        HandlerThread handlerThread = new HandlerThread("");
+        handlerThread.start();
+        mHandler = new Handler(handlerThread.getLooper());
+        /* allowIo */
+        ServiceThread thread = new ServiceThread("TestServiceThread",
+                Process.THREAD_PRIORITY_DEFAULT,
+                true /* allowIo */);
+        thread.start();
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        mAms = new ActivityManagerService(
+                new TestInjector(context), mServiceThreadRule.getThread());
+        mAms.mActivityTaskManager = new ActivityTaskManagerService(context);
+        mAms.mActivityTaskManager.initialize(null, null, context.getMainLooper());
+        mAms.mAtmInternal = spy(mAms.mActivityTaskManager.getAtmInternal());
+        mAms.mPackageManagerInt = mPackageManagerInt;
+        doReturn(new ComponentName("", "")).when(mPackageManagerInt).getSystemUiServiceComponent();
+        LocalServices.removeServiceForTest(PackageManagerInternal.class);
+        LocalServices.addService(PackageManagerInternal.class, mPackageManagerInt);
+
+        mCacheOomRanker.init(mExecutor);
+    }
+
+    @Test
+    public void init_listensForConfigChanges() throws InterruptedException {
+        mExecutor.init();
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                CacheOomRanker.KEY_USE_OOM_RE_RANKING,
+                Boolean.TRUE.toString(), true);
+        mExecutor.waitForLatch();
+        assertThat(mCacheOomRanker.useOomReranking()).isTrue();
+        mExecutor.init();
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                CacheOomRanker.KEY_USE_OOM_RE_RANKING, Boolean.FALSE.toString(), false);
+        mExecutor.waitForLatch();
+        assertThat(mCacheOomRanker.useOomReranking()).isFalse();
+
+        mExecutor.init();
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                CacheOomRanker.KEY_OOM_RE_RANKING_NUMBER_TO_RE_RANK,
+                Integer.toString(CacheOomRanker.DEFAULT_OOM_RE_RANKING_NUMBER_TO_RE_RANK + 2),
+                false);
+        mExecutor.waitForLatch();
+        assertThat(mCacheOomRanker.getNumberToReRank())
+                .isEqualTo(CacheOomRanker.DEFAULT_OOM_RE_RANKING_NUMBER_TO_RE_RANK + 2);
+
+        mExecutor.init();
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                CacheOomRanker.KEY_OOM_RE_RANKING_LRU_WEIGHT,
+                Float.toString(CacheOomRanker.DEFAULT_OOM_RE_RANKING_LRU_WEIGHT + 0.1f),
+                false);
+        mExecutor.waitForLatch();
+        assertThat(mCacheOomRanker.mLruWeight)
+                .isEqualTo(CacheOomRanker.DEFAULT_OOM_RE_RANKING_LRU_WEIGHT + 0.1f);
+
+        mExecutor.init();
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                CacheOomRanker.KEY_OOM_RE_RANKING_RSS_WEIGHT,
+                Float.toString(CacheOomRanker.DEFAULT_OOM_RE_RANKING_RSS_WEIGHT - 0.1f),
+                false);
+        mExecutor.waitForLatch();
+        assertThat(mCacheOomRanker.mRssWeight)
+                .isEqualTo(CacheOomRanker.DEFAULT_OOM_RE_RANKING_RSS_WEIGHT - 0.1f);
+
+        mExecutor.init();
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                CacheOomRanker.KEY_OOM_RE_RANKING_USES_WEIGHT,
+                Float.toString(CacheOomRanker.DEFAULT_OOM_RE_RANKING_USES_WEIGHT + 0.2f),
+                false);
+        mExecutor.waitForLatch();
+        assertThat(mCacheOomRanker.mUsesWeight)
+                .isEqualTo(CacheOomRanker.DEFAULT_OOM_RE_RANKING_USES_WEIGHT + 0.2f);
+    }
+
+    @Test
+    public void reRankLruCachedApps_lruImpactsOrdering() throws InterruptedException {
+        setConfig(/* numberToReRank= */ 5,
+                /* usesWeight= */ 0.0f,
+                /* pssWeight= */ 0.0f,
+                /* lruWeight= */1.0f);
+
+        ProcessList list = new ProcessList();
+        ArrayList<ProcessRecord> processList = list.mLruProcesses;
+        ProcessRecord lastUsed40MinutesAgo = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                Duration.ofMinutes(40).toMillis(), 10 * 1024L, 1000);
+        processList.add(lastUsed40MinutesAgo);
+        ProcessRecord lastUsed42MinutesAgo = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                Duration.ofMinutes(42).toMillis(), 20 * 1024L, 2000);
+        processList.add(lastUsed42MinutesAgo);
+        ProcessRecord lastUsed60MinutesAgo = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                Duration.ofMinutes(60).toMillis(), 1024L, 10000);
+        processList.add(lastUsed60MinutesAgo);
+        ProcessRecord lastUsed15MinutesAgo = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                Duration.ofMinutes(15).toMillis(), 100 * 1024L, 10);
+        processList.add(lastUsed15MinutesAgo);
+        ProcessRecord lastUsed17MinutesAgo = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                Duration.ofMinutes(17).toMillis(), 1024L, 20);
+        processList.add(lastUsed17MinutesAgo);
+        // Only re-ranking 5 entries so this should stay in most recent position.
+        ProcessRecord lastUsed30MinutesAgo = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                Duration.ofMinutes(30).toMillis(), 1024L, 20);
+        processList.add(lastUsed30MinutesAgo);
+
+        mCacheOomRanker.reRankLruCachedApps(list);
+
+        // First 5 ordered by least recently used first, then last processes position unchanged.
+        assertThat(processList).containsExactly(lastUsed60MinutesAgo, lastUsed42MinutesAgo,
+                lastUsed40MinutesAgo, lastUsed17MinutesAgo, lastUsed15MinutesAgo,
+                lastUsed30MinutesAgo);
+    }
+
+    @Test
+    public void reRankLruCachedApps_rssImpactsOrdering() throws InterruptedException {
+        setConfig(/* numberToReRank= */ 6,
+                /* usesWeight= */ 0.0f,
+                /* pssWeight= */ 1.0f,
+                /* lruWeight= */ 0.0f);
+
+        ProcessList list = new ProcessList();
+        ArrayList<ProcessRecord> processList = list.mLruProcesses;
+        ProcessRecord rss10k = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                Duration.ofMinutes(40).toMillis(), 10 * 1024L, 1000);
+        processList.add(rss10k);
+        ProcessRecord rss20k = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                Duration.ofMinutes(42).toMillis(), 20 * 1024L, 2000);
+        processList.add(rss20k);
+        ProcessRecord rss1k = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                Duration.ofMinutes(60).toMillis(), 1024L, 10000);
+        processList.add(rss1k);
+        ProcessRecord rss100k = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                Duration.ofMinutes(15).toMillis(), 100 * 1024L, 10);
+        processList.add(rss100k);
+        ProcessRecord rss2k = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                Duration.ofMinutes(17).toMillis(), 2 * 1024L, 20);
+        processList.add(rss2k);
+        ProcessRecord rss15k = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                Duration.ofMinutes(30).toMillis(), 15 * 1024L, 20);
+        processList.add(rss15k);
+        // Only re-ranking 6 entries so this should stay in most recent position.
+        ProcessRecord rss16k = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                Duration.ofMinutes(30).toMillis(), 16 * 1024L, 20);
+        processList.add(rss16k);
+
+        mCacheOomRanker.reRankLruCachedApps(list);
+
+        // First 6 ordered by largest pss, then last processes position unchanged.
+        assertThat(processList).containsExactly(rss100k, rss20k, rss15k, rss10k, rss2k, rss1k,
+                rss16k);
+    }
+
+    @Test
+    public void reRankLruCachedApps_usesImpactsOrdering() throws InterruptedException {
+        setConfig(/* numberToReRank= */ 4,
+                /* usesWeight= */ 1.0f,
+                /* pssWeight= */ 0.0f,
+                /* lruWeight= */ 0.0f);
+
+        ProcessList list = new ProcessList();
+        list.mLruProcessServiceStart = 1;
+        ArrayList<ProcessRecord> processList = list.mLruProcesses;
+        ProcessRecord used1000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                Duration.ofMinutes(40).toMillis(), 10 * 1024L, 1000);
+        processList.add(used1000);
+        ProcessRecord used2000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                Duration.ofMinutes(42).toMillis(), 20 * 1024L, 2000);
+        processList.add(used2000);
+        ProcessRecord used10 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                Duration.ofMinutes(15).toMillis(), 100 * 1024L, 10);
+        processList.add(used10);
+        ProcessRecord used20 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                Duration.ofMinutes(17).toMillis(), 2 * 1024L, 20);
+        processList.add(used20);
+        // Only re-ranking 6 entries so last two should stay in most recent position.
+        ProcessRecord used500 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                Duration.ofMinutes(30).toMillis(), 15 * 1024L, 500);
+        processList.add(used500);
+        ProcessRecord used200 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                Duration.ofMinutes(30).toMillis(), 16 * 1024L, 200);
+        processList.add(used200);
+
+        mCacheOomRanker.reRankLruCachedApps(list);
+
+        // First 4 ordered by uses, then last processes position unchanged.
+        assertThat(processList).containsExactly(used10, used20, used1000, used2000, used500,
+                used200);
+    }
+
+    @Test
+    public void reRankLruCachedApps_notEnoughProcesses() throws InterruptedException {
+        setConfig(/* numberToReRank= */ 4,
+                /* usesWeight= */ 0.5f,
+                /* pssWeight= */ 0.2f,
+                /* lruWeight= */ 0.3f);
+
+        ProcessList list = new ProcessList();
+        ArrayList<ProcessRecord> processList = list.mLruProcesses;
+        ProcessRecord unknownAdj1 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                Duration.ofMinutes(40).toMillis(), 10 * 1024L, 1000);
+        processList.add(unknownAdj1);
+        ProcessRecord unknownAdj2 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                Duration.ofMinutes(42).toMillis(), 20 * 1024L, 2000);
+        processList.add(unknownAdj2);
+        ProcessRecord unknownAdj3 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                Duration.ofMinutes(15).toMillis(), 100 * 1024L, 10);
+        processList.add(unknownAdj3);
+        ProcessRecord foregroundAdj = nextProcessRecord(ProcessList.FOREGROUND_APP_ADJ,
+                Duration.ofMinutes(17).toMillis(), 2 * 1024L, 20);
+        processList.add(foregroundAdj);
+        ProcessRecord serviceAdj = nextProcessRecord(ProcessList.SERVICE_ADJ,
+                Duration.ofMinutes(30).toMillis(), 15 * 1024L, 500);
+        processList.add(serviceAdj);
+        ProcessRecord systemAdj = nextProcessRecord(ProcessList.SYSTEM_ADJ,
+                Duration.ofMinutes(30).toMillis(), 16 * 1024L, 200);
+        processList.add(systemAdj);
+
+        // 6 Processes but only 3 in eligible for cache so no re-ranking.
+        mCacheOomRanker.reRankLruCachedApps(list);
+
+        // All positions unchanged.
+        assertThat(processList).containsExactly(unknownAdj1, unknownAdj2, unknownAdj3,
+                foregroundAdj, serviceAdj, systemAdj);
+    }
+
+    @Test
+    public void reRankLruCachedApps_notEnoughNonServiceProcesses() throws InterruptedException {
+        setConfig(/* numberToReRank= */ 4,
+                /* usesWeight= */ 1.0f,
+                /* pssWeight= */ 0.0f,
+                /* lruWeight= */ 0.0f);
+
+        ProcessList list = new ProcessList();
+        list.mLruProcessServiceStart = 4;
+        ArrayList<ProcessRecord> processList = list.mLruProcesses;
+        ProcessRecord used1000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                Duration.ofMinutes(40).toMillis(), 10 * 1024L, 1000);
+        processList.add(used1000);
+        ProcessRecord used2000 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                Duration.ofMinutes(42).toMillis(), 20 * 1024L, 2000);
+        processList.add(used2000);
+        ProcessRecord used10 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                Duration.ofMinutes(15).toMillis(), 100 * 1024L, 10);
+        processList.add(used10);
+        ProcessRecord used20 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                Duration.ofMinutes(17).toMillis(), 2 * 1024L, 20);
+        processList.add(used20);
+        ProcessRecord used500 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                Duration.ofMinutes(30).toMillis(), 15 * 1024L, 500);
+        processList.add(used500);
+        ProcessRecord used200 = nextProcessRecord(ProcessList.UNKNOWN_ADJ,
+                Duration.ofMinutes(30).toMillis(), 16 * 1024L, 200);
+        processList.add(used200);
+
+        mCacheOomRanker.reRankLruCachedApps(list);
+
+        // All positions unchanged.
+        assertThat(processList).containsExactly(used1000, used2000, used10, used20, used500,
+                used200);
+    }
+
+    private void setConfig(int numberToReRank, float useWeight, float pssWeight, float lruWeight)
+            throws InterruptedException {
+        mExecutor.init(4);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                CacheOomRanker.KEY_OOM_RE_RANKING_NUMBER_TO_RE_RANK,
+                Integer.toString(numberToReRank),
+                false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                CacheOomRanker.KEY_OOM_RE_RANKING_LRU_WEIGHT,
+                Float.toString(lruWeight),
+                false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                CacheOomRanker.KEY_OOM_RE_RANKING_RSS_WEIGHT,
+                Float.toString(pssWeight),
+                false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                CacheOomRanker.KEY_OOM_RE_RANKING_USES_WEIGHT,
+                Float.toString(useWeight),
+                false);
+        mExecutor.waitForLatch();
+        assertThat(mCacheOomRanker.getNumberToReRank()).isEqualTo(numberToReRank);
+        assertThat(mCacheOomRanker.mRssWeight).isEqualTo(pssWeight);
+        assertThat(mCacheOomRanker.mUsesWeight).isEqualTo(useWeight);
+        assertThat(mCacheOomRanker.mLruWeight).isEqualTo(lruWeight);
+    }
+
+    private ProcessRecord nextProcessRecord(int setAdj, long lastActivityTime, long lastRss,
+            int returnedToCacheCount) {
+        ApplicationInfo ai = new ApplicationInfo();
+        ai.packageName = "a.package.name" + mNextPackageName++;
+        ProcessRecord app = new ProcessRecord(mAms, ai, ai.packageName + ":process", mNextUid++);
+        app.pid = mNextPid++;
+        app.info.uid = mNextPackageUid++;
+        // Exact value does not mater, it can be any state for which compaction is allowed.
+        app.setProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+        app.setAdj = setAdj;
+        app.lastActivityTime = lastActivityTime;
+        app.mLastRss = lastRss;
+        app.setCached(false);
+        for (int i = 0; i < returnedToCacheCount; ++i) {
+            app.setCached(false);
+            app.setCached(true);
+        }
+        return app;
+    }
+
+    private class TestExecutor implements Executor {
+        private CountDownLatch mLatch;
+
+        private void init(int count) {
+            mLatch = new CountDownLatch(count);
+        }
+
+        private void init() {
+            init(1);
+        }
+
+        private void waitForLatch() throws InterruptedException {
+            mLatch.await(5, TimeUnit.SECONDS);
+        }
+
+        @Override
+        public void execute(Runnable command) {
+            command.run();
+            mLatch.countDown();
+        }
+    }
+
+    private class TestInjector extends ActivityManagerService.Injector {
+        private TestInjector(Context context) {
+            super(context);
+        }
+
+        @Override
+        public AppOpsService getAppOpsService(File file, Handler handler) {
+            return mAppOpsService;
+        }
+
+        @Override
+        public Handler getUiHandler(ActivityManagerService service) {
+            return mHandler;
+        }
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
index dcbf8c0..4effa4d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
@@ -59,6 +59,7 @@
 import com.android.server.AppStateTrackerImpl;
 import com.android.server.DeviceIdleInternal;
 import com.android.server.LocalServices;
+import com.android.server.PowerAllowlistInternal;
 import com.android.server.SystemServiceManager;
 import com.android.server.job.controllers.JobStatus;
 import com.android.server.usage.AppStandbyInternal;
@@ -134,6 +135,8 @@
         when(mContext.getPackageManager()).thenReturn(mock(PackageManager.class));
         when(mContext.getResources()).thenReturn(mock(Resources.class));
         // Called in QuotaController constructor.
+        doReturn(mock(PowerAllowlistInternal.class))
+                .when(() -> LocalServices.getService(PowerAllowlistInternal.class));
         IActivityManager activityManager = ActivityManager.getService();
         spyOn(activityManager);
         try {
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 1a65894..c4c9173 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
@@ -80,6 +80,7 @@
 
 import com.android.internal.util.ArrayUtils;
 import com.android.server.LocalServices;
+import com.android.server.PowerAllowlistInternal;
 import com.android.server.job.JobSchedulerService;
 import com.android.server.job.JobSchedulerService.Constants;
 import com.android.server.job.JobServiceContext;
@@ -123,6 +124,7 @@
     private QuotaController mQuotaController;
     private QuotaController.QcConstants mQcConstants;
     private int mSourceUid;
+    private PowerAllowlistInternal.TempAllowlistChangeListener mTempAllowlistListener;
     private IUidObserver mUidObserver;
     DeviceConfig.Properties.Builder mDeviceConfigPropertiesBuilder;
 
@@ -138,6 +140,8 @@
     @Mock
     private PackageManagerInternal mPackageManagerInternal;
     @Mock
+    private PowerAllowlistInternal mPowerAllowlistInternal;
+    @Mock
     private UsageStatsManagerInternal mUsageStatsManager;
 
     private JobStore mJobStore;
@@ -173,6 +177,8 @@
                 .when(() -> LocalServices.getService(BatteryManagerInternal.class));
         doReturn(mUsageStatsManager)
                 .when(() -> LocalServices.getService(UsageStatsManagerInternal.class));
+        doReturn(mPowerAllowlistInternal)
+                .when(() -> LocalServices.getService(PowerAllowlistInternal.class));
         // Used in JobStatus.
         doReturn(mPackageManagerInternal)
                 .when(() -> LocalServices.getService(PackageManagerInternal.class));
@@ -211,11 +217,19 @@
                 ArgumentCaptor.forClass(BroadcastReceiver.class);
         ArgumentCaptor<IUidObserver> uidObserverCaptor =
                 ArgumentCaptor.forClass(IUidObserver.class);
+        ArgumentCaptor<PowerAllowlistInternal.TempAllowlistChangeListener> taChangeCaptor =
+                ArgumentCaptor.forClass(PowerAllowlistInternal.TempAllowlistChangeListener.class);
         mQuotaController = new QuotaController(mJobSchedulerService,
                 mock(BackgroundJobsController.class), mock(ConnectivityController.class));
 
-        verify(mContext).registerReceiver(receiverCaptor.capture(), any());
+        verify(mContext).registerReceiver(receiverCaptor.capture(),
+                ArgumentMatchers.argThat(filter ->
+                        filter.hasAction(BatteryManager.ACTION_CHARGING)
+                                && filter.hasAction(BatteryManager.ACTION_DISCHARGING)));
         mChargingReceiver = receiverCaptor.getValue();
+        verify(mPowerAllowlistInternal)
+                .registerTempAllowlistChangeListener(taChangeCaptor.capture());
+        mTempAllowlistListener = taChangeCaptor.getValue();
         try {
             verify(activityManager).registerUidObserver(
                     uidObserverCaptor.capture(),
@@ -2385,6 +2399,8 @@
         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,
+                84 * SECOND_IN_MILLIS);
 
         assertEquals(5 * MINUTE_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs());
         assertEquals(2 * MINUTE_IN_MILLIS, mQuotaController.getInQuotaBufferMs());
@@ -2423,6 +2439,7 @@
         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());
     }
 
     @Test
@@ -2462,6 +2479,7 @@
         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);
 
         assertEquals(MINUTE_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs());
         assertEquals(0, mQuotaController.getInQuotaBufferMs());
@@ -2497,6 +2515,7 @@
         assertEquals(10 * SECOND_IN_MILLIS, mQuotaController.getEJRewardTopAppMs());
         assertEquals(5 * SECOND_IN_MILLIS, mQuotaController.getEJRewardInteractionMs());
         assertEquals(0, mQuotaController.getEJRewardNotificationSeenMs());
+        assertEquals(0, mQuotaController.getEJTempAllowlistGracePeriodMs());
 
         // Invalid configurations.
         // In_QUOTA_BUFFER should never be greater than ALLOWED_TIME_PER_PERIOD
@@ -2530,6 +2549,7 @@
         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);
 
         assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs());
         assertEquals(5 * MINUTE_IN_MILLIS, mQuotaController.getInQuotaBufferMs());
@@ -2555,6 +2575,7 @@
         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());
     }
 
     /** Tests that TimingSessions aren't saved when the device is charging. */
@@ -3145,6 +3166,119 @@
     }
 
     /**
+     * Tests that Timers properly track regular sessions when an app is added and removed from the
+     * temp allowlist.
+     */
+    @Test
+    public void testTimerTracking_TempAllowlisting() {
+        // None of these should be affected purely by the temp allowlist changing.
+        setDischarging();
+        setProcessState(ActivityManager.PROCESS_STATE_RECEIVER);
+        final long gracePeriodMs = 15 * SECOND_IN_MILLIS;
+        setDeviceConfigLong(QcConstants.KEY_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS, gracePeriodMs);
+        Handler handler = mQuotaController.getHandler();
+        spyOn(handler);
+
+        JobStatus job1 = createJobStatus("testTimerTracking_TempAllowlisting", 1);
+        JobStatus job2 = createJobStatus("testTimerTracking_TempAllowlisting", 2);
+        JobStatus job3 = createJobStatus("testTimerTracking_TempAllowlisting", 3);
+        JobStatus job4 = createJobStatus("testTimerTracking_TempAllowlisting", 4);
+        JobStatus job5 = createJobStatus("testTimerTracking_TempAllowlisting", 5);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(job1, null);
+        }
+        assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+        List<TimingSession> expected = new ArrayList<>();
+
+        long start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(job1);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(job1, job1, true);
+        }
+        expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+        assertEquals(expected,
+                mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        advanceElapsedClock(SECOND_IN_MILLIS);
+
+        // Job starts after app is added to temp allowlist and stops before removal.
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        mTempAllowlistListener.onAppAdded(mSourceUid);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(job2, null);
+            mQuotaController.prepareForExecutionLocked(job2);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(job2, null, false);
+        }
+        expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+        assertEquals(expected,
+                mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        // Job starts after app is added to temp allowlist and stops after removal,
+        // before grace period ends.
+        mTempAllowlistListener.onAppAdded(mSourceUid);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(job3, null);
+            mQuotaController.prepareForExecutionLocked(job3);
+        }
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        mTempAllowlistListener.onAppRemoved(mSourceUid);
+        long elapsedGracePeriodMs = 2 * SECOND_IN_MILLIS;
+        advanceElapsedClock(elapsedGracePeriodMs);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(job3, null, false);
+        }
+        expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS + elapsedGracePeriodMs, 1));
+        assertEquals(expected,
+                mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        advanceElapsedClock(SECOND_IN_MILLIS);
+        elapsedGracePeriodMs += SECOND_IN_MILLIS;
+
+        // Job starts during grace period and ends after grace period ends
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(job4, null);
+            mQuotaController.prepareForExecutionLocked(job4);
+        }
+        final long remainingGracePeriod = gracePeriodMs - elapsedGracePeriodMs;
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        advanceElapsedClock(remainingGracePeriod);
+        // Wait for handler to update Timer
+        // Can't directly evaluate the message because for some reason, the captured message returns
+        // the wrong 'what' even though the correct message goes to the handler and the correct
+        // path executes.
+        verify(handler, timeout(gracePeriodMs + 5 * SECOND_IN_MILLIS)).handleMessage(any());
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        expected.add(createTimingSession(start, remainingGracePeriod + 10 * SECOND_IN_MILLIS, 1));
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(job4, job4, true);
+        }
+        assertEquals(expected,
+                mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        // Job starts and runs completely after temp allowlist grace period.
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(job5, null);
+            mQuotaController.prepareForExecutionLocked(job5);
+        }
+        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.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+    }
+
+    /**
      * Tests that TOP jobs aren't stopped when an app runs out of quota.
      */
     @Test
@@ -4583,6 +4717,116 @@
     }
 
     /**
+     * Tests that Timers properly track sessions when an app is added and removed from the temp
+     * allowlist.
+     */
+    @Test
+    public void testEJTimerTracking_TempAllowlisting() {
+        setDischarging();
+        setProcessState(ActivityManager.PROCESS_STATE_RECEIVER);
+        final long gracePeriodMs = 15 * SECOND_IN_MILLIS;
+        setDeviceConfigLong(QcConstants.KEY_EJ_TEMP_ALLOWLIST_GRACE_PERIOD_MS, gracePeriodMs);
+        Handler handler = mQuotaController.getHandler();
+        spyOn(handler);
+
+        JobStatus job1 = createExpeditedJobStatus("testEJTimerTracking_TempAllowlisting", 1);
+        JobStatus job2 = createExpeditedJobStatus("testEJTimerTracking_TempAllowlisting", 2);
+        JobStatus job3 = createExpeditedJobStatus("testEJTimerTracking_TempAllowlisting", 3);
+        JobStatus job4 = createExpeditedJobStatus("testEJTimerTracking_TempAllowlisting", 4);
+        JobStatus job5 = createExpeditedJobStatus("testEJTimerTracking_TempAllowlisting", 5);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(job1, null);
+        }
+        assertNull(mQuotaController.getEJTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+        List<TimingSession> expected = new ArrayList<>();
+
+        long start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(job1);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(job1, job1, true);
+        }
+        expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+        assertEquals(expected,
+                mQuotaController.getEJTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        advanceElapsedClock(SECOND_IN_MILLIS);
+
+        // Job starts after app is added to temp allowlist and stops before removal.
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        mTempAllowlistListener.onAppAdded(mSourceUid);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(job2, null);
+            mQuotaController.prepareForExecutionLocked(job2);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(job2, null, false);
+        }
+        assertEquals(expected,
+                mQuotaController.getEJTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        // Job starts after app is added to temp allowlist and stops after removal,
+        // before grace period ends.
+        mTempAllowlistListener.onAppAdded(mSourceUid);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(job3, null);
+            mQuotaController.prepareForExecutionLocked(job3);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        mTempAllowlistListener.onAppRemoved(mSourceUid);
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        long elapsedGracePeriodMs = 2 * SECOND_IN_MILLIS;
+        advanceElapsedClock(elapsedGracePeriodMs);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(job3, null, false);
+        }
+        assertEquals(expected,
+                mQuotaController.getEJTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        advanceElapsedClock(SECOND_IN_MILLIS);
+        elapsedGracePeriodMs += SECOND_IN_MILLIS;
+
+        // Job starts during grace period and ends after grace period ends
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(job4, null);
+            mQuotaController.prepareForExecutionLocked(job4);
+        }
+        final long remainingGracePeriod = gracePeriodMs - elapsedGracePeriodMs;
+        start = JobSchedulerService.sElapsedRealtimeClock.millis() + remainingGracePeriod;
+        advanceElapsedClock(remainingGracePeriod);
+        // Wait for handler to update Timer
+        // Can't directly evaluate the message because for some reason, the captured message returns
+        // the wrong 'what' even though the correct message goes to the handler and the correct
+        // path executes.
+        verify(handler, timeout(gracePeriodMs + 5 * SECOND_IN_MILLIS)).handleMessage(any());
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(job4, job4, true);
+        }
+        assertEquals(expected,
+                mQuotaController.getEJTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        // Job starts and runs completely after temp allowlist grace period.
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(job5, null);
+            mQuotaController.prepareForExecutionLocked(job5);
+        }
+        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
diff --git a/services/tests/mockingservicestests/src/com/android/server/utils/quota/OWNERS b/services/tests/mockingservicestests/src/com/android/server/utils/quota/OWNERS
new file mode 100644
index 0000000..2e9e625
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/utils/quota/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/base:/services/core/java/com/android/server/utils/quota/OWNERS
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/VibratorManagerServiceTest.java
index 726536d..0a35db5 100644
--- a/services/tests/servicestests/src/com/android/server/VibratorManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/VibratorManagerServiceTest.java
@@ -24,10 +24,6 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -48,6 +44,7 @@
 
 import androidx.test.InstrumentationRegistry;
 
+import com.android.server.vibrator.FakeVibratorControllerProvider;
 import com.android.server.vibrator.VibratorController;
 
 import org.junit.After;
@@ -81,7 +78,7 @@
     @Mock private PowerManagerInternal mPowerManagerInternalMock;
     @Mock private PowerSaveState mPowerSaveStateMock;
 
-    private final Map<Integer, VibratorController.NativeWrapper> mNativeWrappers = new HashMap<>();
+    private final Map<Integer, FakeVibratorControllerProvider> mVibratorProviders = new HashMap<>();
 
     private TestLooper mTestLooper;
 
@@ -117,8 +114,8 @@
                     @Override
                     VibratorController createVibratorController(int vibratorId,
                             VibratorController.OnVibrationCompleteListener listener) {
-                        return new VibratorController(
-                                vibratorId, listener, mNativeWrappers.get(vibratorId));
+                        return mVibratorProviders.get(vibratorId)
+                                .newVibratorController(vibratorId, listener);
                     }
                 });
         service.systemReady();
@@ -126,9 +123,12 @@
     }
 
     @Test
-    public void createService_initializesNativeService() {
+    public void createService_initializesNativeManagerServiceAndVibrators() {
+        mockVibrators(1, 2);
         createService();
         verify(mNativeWrapperMock).init();
+        assertTrue(mVibratorProviders.get(1).isInitialized());
+        assertTrue(mVibratorProviders.get(2).isInitialized());
     }
 
     @Test
@@ -139,28 +139,23 @@
 
     @Test
     public void getVibratorIds_withNonEmptyResultFromNative_returnsSameArray() {
-        mNativeWrappers.put(1, mockVibrator(/* capabilities= */ 0));
-        mNativeWrappers.put(2, mockVibrator(/* capabilities= */ 0));
-        when(mNativeWrapperMock.getVibratorIds()).thenReturn(new int[]{2, 1});
+        mockVibrators(2, 1);
         assertArrayEquals(new int[]{2, 1}, createService().getVibratorIds());
     }
 
     @Test
     public void getVibratorInfo_withMissingVibratorId_returnsNull() {
-        mockVibrators(mockVibrator(/* capabilities= */ 0));
+        mockVibrators(1);
         assertNull(createService().getVibratorInfo(2));
     }
 
     @Test
     public void getVibratorInfo_withExistingVibratorId_returnsHalInfoForVibrator() {
-        VibratorController.NativeWrapper vibratorMock = mockVibrator(
-                IVibrator.CAP_COMPOSE_EFFECTS | IVibrator.CAP_AMPLITUDE_CONTROL);
-        when(vibratorMock.getSupportedEffects()).thenReturn(
-                new int[]{VibrationEffect.EFFECT_CLICK});
-        when(vibratorMock.getSupportedPrimitives()).thenReturn(
-                new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK});
-        mNativeWrappers.put(1, vibratorMock);
-        when(mNativeWrapperMock.getVibratorIds()).thenReturn(new int[]{1});
+        mockVibrators(1);
+        FakeVibratorControllerProvider vibrator = mVibratorProviders.get(1);
+        vibrator.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS, IVibrator.CAP_AMPLITUDE_CONTROL);
+        vibrator.setSupportedEffects(VibrationEffect.EFFECT_CLICK);
+        vibrator.setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK);
         VibratorInfo info = createService().getVibratorInfo(1);
 
         assertNotNull(info);
@@ -178,105 +173,95 @@
 
     @Test
     public void setAlwaysOnEffect_withMono_enablesAlwaysOnEffectToAllVibratorsWithCapability() {
-        VibratorController.NativeWrapper[] vibratorMocks = new VibratorController.NativeWrapper[]{
-                mockVibrator(IVibrator.CAP_ALWAYS_ON_CONTROL),
-                mockVibrator(/* capabilities= */ 0),
-                mockVibrator(IVibrator.CAP_ALWAYS_ON_CONTROL),
-        };
-        mockVibrators(vibratorMocks);
+        mockVibrators(1, 2, 3);
+        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_ALWAYS_ON_CONTROL);
+        mVibratorProviders.get(3).setCapabilities(IVibrator.CAP_ALWAYS_ON_CONTROL);
 
         CombinedVibrationEffect effect = CombinedVibrationEffect.createSynced(
                 VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
         assertTrue(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS));
 
-        // Only vibrators 0 and 2 have always-on capabilities.
-        verify(vibratorMocks[0]).alwaysOnEnable(
-                eq(1L), eq((long) VibrationEffect.EFFECT_CLICK),
-                eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG));
-        verify(vibratorMocks[1], never()).alwaysOnEnable(anyLong(), anyLong(), anyLong());
-        verify(vibratorMocks[2]).alwaysOnEnable(
-                eq(1L), eq((long) VibrationEffect.EFFECT_CLICK),
-                eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG));
+        VibrationEffect.Prebaked expectedEffect = new VibrationEffect.Prebaked(
+                VibrationEffect.EFFECT_CLICK, false, VibrationEffect.EFFECT_STRENGTH_STRONG);
+
+        // Only vibrators 1 and 3 have always-on capabilities.
+        assertEquals(mVibratorProviders.get(1).getAlwaysOnEffect(1), expectedEffect);
+        assertNull(mVibratorProviders.get(2).getAlwaysOnEffect(1));
+        assertEquals(mVibratorProviders.get(3).getAlwaysOnEffect(1), expectedEffect);
     }
 
     @Test
     public void setAlwaysOnEffect_withStereo_enablesAlwaysOnEffectToAllVibratorsWithCapability() {
-        VibratorController.NativeWrapper[] vibratorMocks = new VibratorController.NativeWrapper[] {
-                mockVibrator(IVibrator.CAP_ALWAYS_ON_CONTROL),
-                mockVibrator(IVibrator.CAP_ALWAYS_ON_CONTROL),
-                mockVibrator(0),
-                mockVibrator(IVibrator.CAP_ALWAYS_ON_CONTROL),
-        };
-        mockVibrators(vibratorMocks);
+        mockVibrators(1, 2, 3, 4);
+        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_ALWAYS_ON_CONTROL);
+        mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_ALWAYS_ON_CONTROL);
+        mVibratorProviders.get(4).setCapabilities(IVibrator.CAP_ALWAYS_ON_CONTROL);
 
         CombinedVibrationEffect effect = CombinedVibrationEffect.startSynced()
-                .addVibrator(0, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK))
-                .addVibrator(1, VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK))
-                .addVibrator(2, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK))
+                .addVibrator(1, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK))
+                .addVibrator(2, VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK))
+                .addVibrator(3, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK))
                 .combine();
         assertTrue(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS));
 
-        // Enables click on vibrator 0 and tick on vibrator 1 only.
-        verify(vibratorMocks[0]).alwaysOnEnable(
-                eq(1L), eq((long) VibrationEffect.EFFECT_CLICK),
-                eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG));
-        verify(vibratorMocks[1]).alwaysOnEnable(
-                eq(1L), eq((long) VibrationEffect.EFFECT_TICK),
-                eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG));
-        verify(vibratorMocks[2], never()).alwaysOnEnable(anyLong(), anyLong(), anyLong());
-        verify(vibratorMocks[3], never()).alwaysOnEnable(anyLong(), anyLong(), anyLong());
+        VibrationEffect.Prebaked expectedClick = new VibrationEffect.Prebaked(
+                VibrationEffect.EFFECT_CLICK, false, VibrationEffect.EFFECT_STRENGTH_STRONG);
+
+        VibrationEffect.Prebaked expectedTick = new VibrationEffect.Prebaked(
+                VibrationEffect.EFFECT_TICK, false, VibrationEffect.EFFECT_STRENGTH_STRONG);
+
+        // Enables click on vibrator 1 and tick on vibrator 2 only.
+        assertEquals(mVibratorProviders.get(1).getAlwaysOnEffect(1), expectedClick);
+        assertEquals(mVibratorProviders.get(2).getAlwaysOnEffect(1), expectedTick);
+        assertNull(mVibratorProviders.get(3).getAlwaysOnEffect(1));
+        assertNull(mVibratorProviders.get(4).getAlwaysOnEffect(1));
     }
 
     @Test
     public void setAlwaysOnEffect_withNullEffect_disablesAlwaysOnEffects() {
-        VibratorController.NativeWrapper[] vibratorMocks = new VibratorController.NativeWrapper[] {
-                mockVibrator(IVibrator.CAP_ALWAYS_ON_CONTROL),
-                mockVibrator(0),
-                mockVibrator(IVibrator.CAP_ALWAYS_ON_CONTROL),
-        };
-        mockVibrators(vibratorMocks);
+        mockVibrators(1, 2, 3);
+        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_ALWAYS_ON_CONTROL);
+        mVibratorProviders.get(3).setCapabilities(IVibrator.CAP_ALWAYS_ON_CONTROL);
+
+        CombinedVibrationEffect effect = CombinedVibrationEffect.createSynced(
+                VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
+        assertTrue(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS));
 
         assertTrue(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1, null, ALARM_ATTRS));
 
-        // Disables only 0 and 2 that have capability.
-        verify(vibratorMocks[0]).alwaysOnDisable(eq(1L));
-        verify(vibratorMocks[1], never()).alwaysOnDisable(anyLong());
-        verify(vibratorMocks[2]).alwaysOnDisable(eq(1L));
+        assertNull(mVibratorProviders.get(1).getAlwaysOnEffect(1));
+        assertNull(mVibratorProviders.get(2).getAlwaysOnEffect(1));
+        assertNull(mVibratorProviders.get(3).getAlwaysOnEffect(1));
     }
 
     @Test
     public void setAlwaysOnEffect_withNonPrebakedEffect_ignoresEffect() {
-        VibratorController.NativeWrapper vibratorMock =
-                mockVibrator(IVibrator.CAP_ALWAYS_ON_CONTROL);
-        mockVibrators(vibratorMock);
+        mockVibrators(1);
+        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_ALWAYS_ON_CONTROL);
 
         CombinedVibrationEffect effect = CombinedVibrationEffect.createSynced(
                 VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE));
         assertFalse(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS));
 
-        verify(vibratorMock, never()).alwaysOnEnable(anyLong(), anyLong(), anyLong());
-        verify(vibratorMock, never()).alwaysOnDisable(anyLong());
+        assertNull(mVibratorProviders.get(1).getAlwaysOnEffect(1));
     }
 
     @Test
     public void setAlwaysOnEffect_withNonSyncedEffect_ignoresEffect() {
-        VibratorController.NativeWrapper vibratorMock =
-                mockVibrator(IVibrator.CAP_ALWAYS_ON_CONTROL);
-        mockVibrators(vibratorMock);
+        mockVibrators(1);
+        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_ALWAYS_ON_CONTROL);
 
         CombinedVibrationEffect effect = CombinedVibrationEffect.startSequential()
                 .addNext(0, VibrationEffect.get(VibrationEffect.EFFECT_CLICK))
                 .combine();
         assertFalse(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS));
 
-        verify(vibratorMock, never()).alwaysOnEnable(anyLong(), anyLong(), anyLong());
-        verify(vibratorMock, never()).alwaysOnDisable(anyLong());
+        assertNull(mVibratorProviders.get(1).getAlwaysOnEffect(1));
     }
 
     @Test
     public void setAlwaysOnEffect_withNoVibratorWithCapability_ignoresEffect() {
-        VibratorController.NativeWrapper vibratorMock = mockVibrator(0);
-        mockVibrators(vibratorMock);
+        mockVibrators(1);
         VibratorManagerService service = createService();
 
         CombinedVibrationEffect mono = CombinedVibrationEffect.createSynced(
@@ -287,8 +272,7 @@
         assertFalse(service.setAlwaysOnEffect(UID, PACKAGE_NAME, 1, mono, ALARM_ATTRS));
         assertFalse(service.setAlwaysOnEffect(UID, PACKAGE_NAME, 2, stereo, ALARM_ATTRS));
 
-        verify(vibratorMock, never()).alwaysOnEnable(anyLong(), anyLong(), anyLong());
-        verify(vibratorMock, never()).alwaysOnDisable(anyLong());
+        assertNull(mVibratorProviders.get(1).getAlwaysOnEffect(1));
     }
 
     @Test
@@ -310,19 +294,12 @@
                 "Not implemented", () -> service.cancelVibrate(service));
     }
 
-    private VibratorController.NativeWrapper mockVibrator(int capabilities) {
-        VibratorController.NativeWrapper wrapper = mock(VibratorController.NativeWrapper.class);
-        when(wrapper.getCapabilities()).thenReturn((long) capabilities);
-        return wrapper;
-    }
-
-    private void mockVibrators(VibratorController.NativeWrapper... wrappers) {
-        int[] ids = new int[wrappers.length];
-        for (int i = 0; i < wrappers.length; i++) {
-            ids[i] = i;
-            mNativeWrappers.put(i, wrappers[i]);
+    private void mockVibrators(int... vibratorIds) {
+        for (int vibratorId : vibratorIds) {
+            mVibratorProviders.put(vibratorId,
+                    new FakeVibratorControllerProvider(mTestLooper.getLooper()));
         }
-        when(mNativeWrapperMock.getVibratorIds()).thenReturn(ids);
+        when(mNativeWrapperMock.getVibratorIds()).thenReturn(vibratorIds);
     }
 
     private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
diff --git a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
index 32ca7b5..5c1e021 100644
--- a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
@@ -19,21 +19,17 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.AdditionalMatchers.gt;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.intThat;
-import static org.mockito.ArgumentMatchers.notNull;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.never;
+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 static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
 import android.app.AppOpsManager;
@@ -54,8 +50,6 @@
 import android.os.PowerManagerInternal;
 import android.os.PowerSaveState;
 import android.os.Process;
-import android.os.RemoteException;
-import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.VibrationAttributes;
 import android.os.VibrationEffect;
@@ -70,16 +64,16 @@
 
 import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.internal.util.test.FakeSettingsProviderRule;
+import com.android.server.vibrator.FakeVibrator;
+import com.android.server.vibrator.FakeVibratorControllerProvider;
 import com.android.server.vibrator.VibratorController;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
-import org.mockito.ArgumentCaptor;
 import org.mockito.InOrder;
 import org.mockito.Mock;
-import org.mockito.Mockito;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
@@ -87,7 +81,7 @@
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicLong;
+import java.util.stream.Collectors;
 
 /**
  * Tests for {@link VibratorService}.
@@ -99,6 +93,7 @@
 public class VibratorServiceTest {
 
     private static final int UID = Process.ROOT_UID;
+    private static final int VIBRATOR_ID = 1;
     private static final String PACKAGE_NAME = "package";
     private static final PowerSaveState NORMAL_POWER_STATE = new PowerSaveState.Builder().build();
     private static final PowerSaveState LOW_POWER_STATE = new PowerSaveState.Builder()
@@ -120,10 +115,7 @@
 
     @Mock private PackageManagerInternal mPackageManagerInternalMock;
     @Mock private PowerManagerInternal mPowerManagerInternalMock;
-    // TODO(b/131311651): replace with a FakeVibrator instead.
-    @Mock private Vibrator mVibratorMock;
     @Mock private AppOpsManager mAppOpsManagerMock;
-    @Mock private VibratorController.NativeWrapper mNativeWrapperMock;
     @Mock private IVibratorStateListener mVibratorStateListenerMock;
     @Mock private IInputManager mIInputManagerMock;
     @Mock private IBinder mVibratorStateListenerBinderMock;
@@ -131,24 +123,22 @@
     private TestLooper mTestLooper;
     private ContextWrapper mContextSpy;
     private PowerManagerInternal.LowPowerModeListener mRegisteredPowerModeListener;
+    private FakeVibrator mFakeVibrator;
+    private FakeVibratorControllerProvider mVibratorProvider;
 
     @Before
     public void setUp() throws Exception {
         mTestLooper = new TestLooper();
+        mFakeVibrator = new FakeVibrator();
+        mVibratorProvider = new FakeVibratorControllerProvider(mTestLooper.getLooper());
         mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
         InputManager inputManager = InputManager.resetInstance(mIInputManagerMock);
 
         ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy);
         when(mContextSpy.getContentResolver()).thenReturn(contentResolver);
-        when(mContextSpy.getSystemService(eq(Context.VIBRATOR_SERVICE))).thenReturn(mVibratorMock);
+        when(mContextSpy.getSystemService(eq(Context.VIBRATOR_SERVICE))).thenReturn(mFakeVibrator);
         when(mContextSpy.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(inputManager);
         when(mContextSpy.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManagerMock);
-        when(mVibratorMock.getDefaultHapticFeedbackIntensity())
-                .thenReturn(Vibrator.VIBRATION_INTENSITY_MEDIUM);
-        when(mVibratorMock.getDefaultNotificationVibrationIntensity())
-                .thenReturn(Vibrator.VIBRATION_INTENSITY_MEDIUM);
-        when(mVibratorMock.getDefaultRingVibrationIntensity())
-                .thenReturn(Vibrator.VIBRATION_INTENSITY_MEDIUM);
         when(mVibratorStateListenerMock.asBinder()).thenReturn(mVibratorStateListenerBinderMock);
         when(mPackageManagerInternalMock.getSystemUiServiceComponent())
                 .thenReturn(new ComponentName("", ""));
@@ -183,7 +173,7 @@
                     @Override
                     VibratorController createVibratorController(
                             VibratorController.OnVibrationCompleteListener listener) {
-                        return new VibratorController(0, listener, mNativeWrapperMock);
+                        return mVibratorProvider.newVibratorController(VIBRATOR_ID, listener);
                     }
 
                     @Override
@@ -203,25 +193,23 @@
     @Test
     public void createService_initializesNativeService() {
         createService();
-        verify(mNativeWrapperMock).init(eq(0), notNull());
-        verify(mNativeWrapperMock, times(2)).off(); // Called from constructor and onSystemReady
+        assertTrue(mVibratorProvider.isInitialized());
     }
 
     @Test
     public void hasVibrator_withVibratorHalPresent_returnsTrue() {
-        when(mNativeWrapperMock.isAvailable()).thenReturn(true);
         assertTrue(createService().hasVibrator());
     }
 
     @Test
     public void hasVibrator_withNoVibratorHalPresent_returnsFalse() {
-        when(mNativeWrapperMock.isAvailable()).thenReturn(false);
+        mVibratorProvider.disableVibrators();
         assertFalse(createService().hasVibrator());
     }
 
     @Test
     public void hasAmplitudeControl_withAmplitudeControlSupport_returnsTrue() {
-        mockVibratorCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        mVibratorProvider.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         assertTrue(createService().hasAmplitudeControl());
     }
 
@@ -234,18 +222,17 @@
     public void hasAmplitudeControl_withInputDevices_returnsTrue() throws Exception {
         when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{1});
         when(mIInputManagerMock.getInputDevice(1)).thenReturn(createInputDeviceWithVibrator(1));
-        mockVibratorCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        mVibratorProvider.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 1);
         assertTrue(createService().hasAmplitudeControl());
     }
 
     @Test
     public void getVibratorInfo_returnsSameInfoFromNative() {
-        mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS | IVibrator.CAP_AMPLITUDE_CONTROL);
-        when(mNativeWrapperMock.getSupportedEffects())
-                .thenReturn(new int[]{VibrationEffect.EFFECT_CLICK});
-        when(mNativeWrapperMock.getSupportedPrimitives())
-                .thenReturn(new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK});
+        mVibratorProvider.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS,
+                IVibrator.CAP_AMPLITUDE_CONTROL);
+        mVibratorProvider.setSupportedEffects(VibrationEffect.EFFECT_CLICK);
+        mVibratorProvider.setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK);
 
         VibratorInfo info = createService().getVibratorInfo();
         assertTrue(info.hasAmplitudeControl());
@@ -258,7 +245,7 @@
     }
 
     @Test
-    public void vibrate_withRingtone_usesRingtoneSettings() {
+    public void vibrate_withRingtone_usesRingtoneSettings() throws Exception {
         setRingerMode(AudioManager.RINGER_MODE_NORMAL);
         setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
         setGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 0);
@@ -266,34 +253,34 @@
 
         setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
         setGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 1);
-        vibrate(createService(), VibrationEffect.createOneShot(10, 10), RINGTONE_ATTRS);
+        vibrateAndWait(createService(), VibrationEffect.createOneShot(10, 10), RINGTONE_ATTRS);
 
         setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1);
         setGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 0);
-        vibrate(createService(), VibrationEffect.createOneShot(100, 100), RINGTONE_ATTRS);
+        vibrateAndWait(createService(), VibrationEffect.createOneShot(100, 100), RINGTONE_ATTRS);
 
-        InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
-        inOrderVerifier.verify(mNativeWrapperMock, never()).on(eq(1L), anyLong());
-        inOrderVerifier.verify(mNativeWrapperMock).on(eq(10L), anyLong());
-        inOrderVerifier.verify(mNativeWrapperMock).on(eq(100L), anyLong());
+        List<VibrationEffect> effects = mVibratorProvider.getEffects();
+        assertEquals(2, effects.size());
+        assertEquals(10, effects.get(0).getDuration());
+        assertEquals(100, effects.get(1).getDuration());
     }
 
     @Test
-    public void vibrate_withPowerModeChange_usesLowPowerModeState() {
+    public void vibrate_withPowerModeChange_usesLowPowerModeState() throws Exception {
         VibratorService service = createService();
         mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE);
         vibrate(service, VibrationEffect.createOneShot(1, 1), HAPTIC_FEEDBACK_ATTRS);
-        vibrate(service, VibrationEffect.createOneShot(2, 2), RINGTONE_ATTRS);
+        vibrateAndWait(service, VibrationEffect.createOneShot(2, 2), RINGTONE_ATTRS);
 
         mRegisteredPowerModeListener.onLowPowerModeChanged(NORMAL_POWER_STATE);
-        vibrate(service, VibrationEffect.createOneShot(3, 3), /* attributes= */ null);
-        vibrate(service, VibrationEffect.createOneShot(4, 4), NOTIFICATION_ATTRS);
+        vibrateAndWait(service, VibrationEffect.createOneShot(3, 3), /* attributes= */ null);
+        vibrateAndWait(service, VibrationEffect.createOneShot(4, 4), NOTIFICATION_ATTRS);
 
-        InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
-        inOrderVerifier.verify(mNativeWrapperMock, never()).on(eq(1L), anyLong());
-        inOrderVerifier.verify(mNativeWrapperMock).on(eq(2L), anyLong());
-        inOrderVerifier.verify(mNativeWrapperMock).on(eq(3L), anyLong());
-        inOrderVerifier.verify(mNativeWrapperMock).on(eq(4L), anyLong());
+        List<VibrationEffect> effects = mVibratorProvider.getEffects();
+        assertEquals(3, effects.size());
+        assertEquals(2, effects.get(0).getDuration());
+        assertEquals(3, effects.get(1).getDuration());
+        assertEquals(4, effects.get(2).getDuration());
     }
 
     @Test
@@ -349,55 +336,55 @@
         when(mIInputManagerMock.getInputDevice(1)).thenReturn(createInputDeviceWithVibrator(1));
         setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 1);
         VibratorService service = createService();
-        Mockito.clearInvocations(mNativeWrapperMock);
 
         VibrationEffect effect = VibrationEffect.createOneShot(100, 128);
-        vibrate(service, effect);
-        assertFalse(service.isVibrating());
-
+        vibrate(service, effect, ALARM_ATTRS);
         verify(mIInputManagerMock).vibrate(eq(1), eq(effect), any());
-        verify(mNativeWrapperMock, never()).on(anyLong(), anyLong());
+
+        // VibrationThread will start this vibration async, so wait before checking it never played.
+        Thread.sleep(10);
+        assertTrue(mVibratorProvider.getEffects().isEmpty());
     }
 
     @Test
-    public void vibrate_withOneShotAndAmplitudeControl_turnsVibratorOnAndSetsAmplitude() {
-        mockVibratorCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+    public void vibrate_withOneShotAndAmplitudeControl_turnsVibratorOnAndSetsAmplitude()
+            throws Exception {
+        mVibratorProvider.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         VibratorService service = createService();
-        Mockito.clearInvocations(mNativeWrapperMock);
 
-        vibrate(service, VibrationEffect.createOneShot(100, 128));
-        assertTrue(service.isVibrating());
+        vibrateAndWait(service, VibrationEffect.createOneShot(100, 128), ALARM_ATTRS);
 
-        verify(mNativeWrapperMock).off();
-        verify(mNativeWrapperMock).on(eq(100L), gt(0L));
-        verify(mNativeWrapperMock).setAmplitude(eq(128));
+        List<VibrationEffect> effects = mVibratorProvider.getEffects();
+        assertEquals(1, effects.size());
+        assertEquals(100, effects.get(0).getDuration());
+        assertEquals(Arrays.asList(128), mVibratorProvider.getAmplitudes());
     }
 
     @Test
-    public void vibrate_withOneShotAndNoAmplitudeControl_turnsVibratorOnAndIgnoresAmplitude() {
+    public void vibrate_withOneShotAndNoAmplitudeControl_turnsVibratorOnAndIgnoresAmplitude()
+            throws Exception {
         VibratorService service = createService();
-        Mockito.clearInvocations(mNativeWrapperMock);
+        clearInvocations();
 
-        vibrate(service, VibrationEffect.createOneShot(100, 128));
-        assertTrue(service.isVibrating());
+        vibrateAndWait(service, VibrationEffect.createOneShot(100, 128), ALARM_ATTRS);
 
-        verify(mNativeWrapperMock).off();
-        verify(mNativeWrapperMock).on(eq(100L), gt(0L));
-        verify(mNativeWrapperMock, never()).setAmplitude(anyInt());
+        List<VibrationEffect> effects = mVibratorProvider.getEffects();
+        assertEquals(1, effects.size());
+        assertEquals(100, effects.get(0).getDuration());
+        assertTrue(mVibratorProvider.getAmplitudes().isEmpty());
     }
 
     @Test
-    public void vibrate_withPrebaked_performsEffect() {
-        when(mNativeWrapperMock.getSupportedEffects())
-                .thenReturn(new int[]{VibrationEffect.EFFECT_CLICK});
+    public void vibrate_withPrebaked_performsEffect() throws Exception {
+        mVibratorProvider.setSupportedEffects(VibrationEffect.EFFECT_CLICK);
         VibratorService service = createService();
-        Mockito.clearInvocations(mNativeWrapperMock);
 
-        vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
+        VibrationEffect effect = VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK);
+        vibrateAndWait(service, effect, ALARM_ATTRS);
 
-        verify(mNativeWrapperMock).off();
-        verify(mNativeWrapperMock).perform(eq((long) VibrationEffect.EFFECT_CLICK),
-                eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), gt(0L));
+        VibrationEffect.Prebaked expectedEffect = new VibrationEffect.Prebaked(
+                VibrationEffect.EFFECT_CLICK, false, VibrationEffect.EFFECT_STRENGTH_STRONG);
+        assertEquals(Arrays.asList(expectedEffect), mVibratorProvider.getEffects());
     }
 
     @Test
@@ -407,120 +394,62 @@
         when(mIInputManagerMock.getInputDevice(1)).thenReturn(createInputDeviceWithVibrator(1));
         setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 1);
         VibratorService service = createService();
-        Mockito.clearInvocations(mNativeWrapperMock);
 
-        vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK));
-        assertFalse(service.isVibrating());
-
-        // Wait for VibrateThread to turn input device vibrator ON.
-        Thread.sleep(5);
+        vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), ALARM_ATTRS);
         verify(mIInputManagerMock).vibrate(eq(1), any(), any());
-        verify(mNativeWrapperMock, never()).on(anyLong(), anyLong());
-        verify(mNativeWrapperMock, never()).perform(anyLong(), anyLong(), anyLong());
+
+        // VibrationThread will start this vibration async, so wait before checking it never played.
+        Thread.sleep(10);
+        assertTrue(mVibratorProvider.getEffects().isEmpty());
     }
 
     @Test
-    public void vibrate_withComposed_performsEffect() {
-        mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+    public void vibrate_withComposed_performsEffect() throws Exception {
+        mVibratorProvider.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
         VibratorService service = createService();
-        Mockito.clearInvocations(mNativeWrapperMock);
 
         VibrationEffect effect = VibrationEffect.startComposition()
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 0.5f, 10)
                 .compose();
-        vibrate(service, effect);
-
-        ArgumentCaptor<VibrationEffect.Composition.PrimitiveEffect[]> primitivesCaptor =
-                ArgumentCaptor.forClass(VibrationEffect.Composition.PrimitiveEffect[].class);
-
-        verify(mNativeWrapperMock).off();
-        verify(mNativeWrapperMock).compose(primitivesCaptor.capture(), gt(0L));
-
-        // Check all primitive effect fields are passed down to the HAL.
-        assertEquals(1, primitivesCaptor.getValue().length);
-        VibrationEffect.Composition.PrimitiveEffect primitive = primitivesCaptor.getValue()[0];
-        assertEquals(VibrationEffect.Composition.PRIMITIVE_CLICK, primitive.id);
-        assertEquals(0.5f, primitive.scale, /* delta= */ 1e-2);
-        assertEquals(10, primitive.delay);
+        vibrateAndWait(service, effect, ALARM_ATTRS);
+        assertEquals(Arrays.asList(effect), mVibratorProvider.getEffects());
     }
 
     @Test
-    public void vibrate_withComposedAndInputDevices_vibratesInputDevices()
-            throws Exception {
+    public void vibrate_withComposedAndInputDevices_vibratesInputDevices() throws Exception {
         when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{1, 2});
         when(mIInputManagerMock.getInputDevice(1)).thenReturn(createInputDeviceWithVibrator(1));
         when(mIInputManagerMock.getInputDevice(2)).thenReturn(createInputDeviceWithVibrator(2));
         setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 1);
         VibratorService service = createService();
-        Mockito.clearInvocations(mNativeWrapperMock);
 
         VibrationEffect effect = VibrationEffect.startComposition()
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 0.5f, 10)
                 .compose();
-        vibrate(service, effect);
-        assertFalse(service.isVibrating());
+        vibrate(service, effect, ALARM_ATTRS);
+        InOrder inOrderVerifier = inOrder(mIInputManagerMock);
+        inOrderVerifier.verify(mIInputManagerMock).vibrate(eq(1), eq(effect), any());
+        inOrderVerifier.verify(mIInputManagerMock).vibrate(eq(2), eq(effect), any());
 
-        verify(mIInputManagerMock).vibrate(eq(1), eq(effect), any());
-        verify(mIInputManagerMock).vibrate(eq(2), eq(effect), any());
-        verify(mNativeWrapperMock, never()).compose(any(), anyLong());
+        // VibrationThread will start this vibration async, so wait before checking it never played.
+        Thread.sleep(10);
+        assertTrue(mVibratorProvider.getEffects().isEmpty());
     }
 
     @Test
     public void vibrate_withWaveform_controlsVibratorAmplitudeDuringTotalVibrationTime()
             throws Exception {
-        mockVibratorCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        mVibratorProvider.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         VibratorService service = createService();
-        Mockito.clearInvocations(mNativeWrapperMock);
 
         VibrationEffect effect = VibrationEffect.createWaveform(
                 new long[]{10, 10, 10}, new int[]{100, 200, 50}, -1);
-        vibrate(service, effect);
+        vibrateAndWait(service, effect, ALARM_ATTRS);
 
-        // Wait for VibrateThread to finish: 10ms 100, 10ms 200, 10ms 50.
-        Thread.sleep(40);
-        InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
-        inOrderVerifier.verify(mNativeWrapperMock).off();
-        inOrderVerifier.verify(mNativeWrapperMock).on(eq(30L), anyLong());
-        inOrderVerifier.verify(mNativeWrapperMock).setAmplitude(eq(100));
-        inOrderVerifier.verify(mNativeWrapperMock).setAmplitude(eq(200));
-        inOrderVerifier.verify(mNativeWrapperMock).setAmplitude(eq(50));
-        inOrderVerifier.verify(mNativeWrapperMock).off();
-    }
-
-    @Test
-    public void vibrate_withWaveform_totalVibrationTimeRespected() throws Exception {
-        int totalDuration = 10_000; // 10s
-        int stepDuration = 25; // 25ms
-
-        // 25% of the first waveform step will be spent on the native on() call.
-        mockVibratorCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
-        doAnswer(invocation -> {
-            Thread.currentThread().sleep(stepDuration / 4);
-            return null;
-        }).when(mNativeWrapperMock).on(anyLong(), anyLong());
-        // 25% of each waveform step will be spent on the native setAmplitude() call..
-        doAnswer(invocation -> {
-            Thread.currentThread().sleep(stepDuration / 4);
-            return null;
-        }).when(mNativeWrapperMock).setAmplitude(anyInt());
-
-        VibratorService service = createService();
-
-        int stepCount = totalDuration / stepDuration;
-        long[] timings = new long[stepCount];
-        int[] amplitudes = new int[stepCount];
-        Arrays.fill(timings, stepDuration);
-        Arrays.fill(amplitudes, VibrationEffect.DEFAULT_AMPLITUDE);
-        VibrationEffect effect = VibrationEffect.createWaveform(timings, amplitudes, -1);
-
-        int perceivedDuration = vibrateAndMeasure(service, effect, /* timeoutSecs= */ 15);
-        int delay = Math.abs(perceivedDuration - totalDuration);
-
-        // Allow some delay for thread scheduling and callback triggering.
-        int maxDelay = (int) (0.05 * totalDuration); // < 5% of total duration
-        assertTrue("Waveform with perceived delay of " + delay + "ms,"
-                        + " expected less than " + maxDelay + "ms",
-                delay < maxDelay);
+        assertEquals(Arrays.asList(100, 200, 50), mVibratorProvider.getAmplitudes());
+        assertEquals(
+                Arrays.asList(VibrationEffect.createOneShot(30, VibrationEffect.DEFAULT_AMPLITUDE)),
+                mVibratorProvider.getEffects());
     }
 
     @Test
@@ -529,123 +458,52 @@
         when(mIInputManagerMock.getInputDevice(1)).thenReturn(createInputDeviceWithVibrator(1));
         setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 1);
         VibratorService service = createService();
-        Mockito.clearInvocations(mNativeWrapperMock);
 
         VibrationEffect effect = VibrationEffect.createWaveform(
                 new long[]{10, 10, 10}, new int[]{100, 200, 50}, -1);
-        vibrate(service, effect);
-        assertFalse(service.isVibrating());
-
-        // Wait for VibrateThread to turn input device vibrator ON.
-        Thread.sleep(5);
+        vibrate(service, effect, ALARM_ATTRS);
         verify(mIInputManagerMock).vibrate(eq(1), eq(effect), any());
-        verify(mNativeWrapperMock, never()).on(anyLong(), anyLong());
+
+        // VibrationThread will start this vibration async, so wait before checking it never played.
+        Thread.sleep(10);
+        assertTrue(mVibratorProvider.getEffects().isEmpty());
     }
 
     @Test
-    public void vibrate_withOneShotAndNativeCallbackTriggered_finishesVibration() {
+    public void vibrate_withNativeCallbackTriggered_finishesVibration() throws Exception {
+        mVibratorProvider.setSupportedEffects(VibrationEffect.EFFECT_CLICK);
         VibratorService service = createService();
-        doAnswer(invocation -> {
-            service.onVibrationComplete(invocation.getArgument(1));
-            return null;
-        }).when(mNativeWrapperMock).on(anyLong(), anyLong());
-        Mockito.clearInvocations(mNativeWrapperMock);
 
-        vibrate(service, VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE));
+        vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), ALARM_ATTRS);
 
-        InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
-        inOrderVerifier.verify(mNativeWrapperMock).off();
-        inOrderVerifier.verify(mNativeWrapperMock).on(eq(100L), gt(0L));
-        inOrderVerifier.verify(mNativeWrapperMock).off();
-    }
-
-    @Test
-    public void vibrate_withPrebakedAndNativeCallbackTriggered_finishesVibration() {
-        when(mNativeWrapperMock.getSupportedEffects())
-                .thenReturn(new int[]{VibrationEffect.EFFECT_CLICK});
-        VibratorService service = createService();
-        doAnswer(invocation -> {
-            service.onVibrationComplete(invocation.getArgument(2));
-            return 10_000L; // 10s
-        }).when(mNativeWrapperMock).perform(anyLong(), anyLong(), anyLong());
-        Mockito.clearInvocations(mNativeWrapperMock);
-
-        vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
-
-        InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
-        inOrderVerifier.verify(mNativeWrapperMock).off();
-        inOrderVerifier.verify(mNativeWrapperMock).perform(
-                eq((long) VibrationEffect.EFFECT_CLICK),
-                eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG),
-                gt(0L));
-        inOrderVerifier.verify(mNativeWrapperMock).off();
-    }
-
-    @Test
-    public void vibrate_withWaveformAndNativeCallback_callbackIgnoredAndWaveformPlaysCompletely()
-            throws Exception {
-        VibratorService service = createService();
-        doAnswer(invocation -> {
-            service.onVibrationComplete(invocation.getArgument(1));
-            return null;
-        }).when(mNativeWrapperMock).on(anyLong(), anyLong());
-        Mockito.clearInvocations(mNativeWrapperMock);
-
-        VibrationEffect effect = VibrationEffect.createWaveform(new long[]{1, 3, 1, 2}, -1);
-        vibrate(service, effect);
-
-        // Wait for VibrateThread to finish: 1ms OFF, 3ms ON, 1ms OFF, 2ms ON.
-        Thread.sleep(15);
-        InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
-        inOrderVerifier.verify(mNativeWrapperMock, times(2)).off();
-        inOrderVerifier.verify(mNativeWrapperMock).on(eq(3L), anyLong());
-        inOrderVerifier.verify(mNativeWrapperMock).off();
-        inOrderVerifier.verify(mNativeWrapperMock).on(eq(2L), anyLong());
-        inOrderVerifier.verify(mNativeWrapperMock).off();
-    }
-
-    @Test
-    public void vibrate_withComposedAndNativeCallbackTriggered_finishesVibration() {
-        mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
-        VibratorService service = createService();
-        doAnswer(invocation -> {
-            service.onVibrationComplete(invocation.getArgument(1));
-            return null;
-        }).when(mNativeWrapperMock).compose(any(), anyLong());
-        Mockito.clearInvocations(mNativeWrapperMock);
-
-        VibrationEffect effect = VibrationEffect.startComposition()
-                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 10)
-                .compose();
-        vibrate(service, effect);
-
-        InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
-        inOrderVerifier.verify(mNativeWrapperMock).off();
-        inOrderVerifier.verify(mNativeWrapperMock).compose(
-                any(VibrationEffect.Composition.PrimitiveEffect[].class), gt(0L));
-        inOrderVerifier.verify(mNativeWrapperMock).off();
-    }
-
-    @Test
-    public void cancelVibrate_withDeviceVibrating_callsoff() {
-        VibratorService service = createService();
-        vibrate(service, VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE));
+        // VibrationThread will start this vibration async, so wait before triggering callbacks.
+        Thread.sleep(10);
         assertTrue(service.isVibrating());
-        Mockito.clearInvocations(mNativeWrapperMock);
 
-        service.cancelVibrate(service);
+        // Trigger callbacks from controller.
+        mTestLooper.moveTimeForward(50);
+        mTestLooper.dispatchAll();
+
+        // VibrationThread needs some time to react to native callbacks and stop the vibrator.
+        Thread.sleep(10);
         assertFalse(service.isVibrating());
-        verify(mNativeWrapperMock).off();
     }
 
     @Test
-    public void cancelVibrate_withDeviceNotVibrating_ignoresCall() {
+    public void cancelVibrate_withDeviceVibrating_callsOff() throws Exception {
         VibratorService service = createService();
-        Mockito.clearInvocations(mNativeWrapperMock);
+
+        vibrate(service, VibrationEffect.createOneShot(100, 100), ALARM_ATTRS);
+
+        // VibrationThread will start this vibration async, so wait before checking.
+        Thread.sleep(10);
+        assertTrue(service.isVibrating());
 
         service.cancelVibrate(service);
+
+        // VibrationThread will stop this vibration async, so wait before checking.
+        Thread.sleep(10);
         assertFalse(service.isVibrating());
-        verify(mNativeWrapperMock, never()).off();
     }
 
     @Test
@@ -653,12 +511,11 @@
         VibratorService service = createService();
         service.registerVibratorStateListener(mVibratorStateListenerMock);
 
-        vibrate(service, VibrationEffect.createOneShot(10, VibrationEffect.DEFAULT_AMPLITUDE));
-        service.cancelVibrate(service);
+        vibrateAndWait(service, VibrationEffect.createOneShot(100, 100), ALARM_ATTRS);
 
         InOrder inOrderVerifier = inOrder(mVibratorStateListenerMock);
         // First notification done when listener is registered.
-        inOrderVerifier.verify(mVibratorStateListenerMock).onVibrating(false);
+        inOrderVerifier.verify(mVibratorStateListenerMock).onVibrating(eq(false));
         inOrderVerifier.verify(mVibratorStateListenerMock).onVibrating(eq(true));
         inOrderVerifier.verify(mVibratorStateListenerMock).onVibrating(eq(false));
         inOrderVerifier.verifyNoMoreInteractions();
@@ -671,18 +528,25 @@
         service.registerVibratorStateListener(mVibratorStateListenerMock);
         verify(mVibratorStateListenerMock).onVibrating(false);
 
-        vibrate(service, VibrationEffect.createOneShot(5, VibrationEffect.DEFAULT_AMPLITUDE));
-        verify(mVibratorStateListenerMock).onVibrating(true);
+        vibrate(service, VibrationEffect.createOneShot(100, 100), ALARM_ATTRS);
 
+        // VibrationThread will start this vibration async, so wait before triggering callbacks.
+        Thread.sleep(10);
         service.unregisterVibratorStateListener(mVibratorStateListenerMock);
-        Mockito.clearInvocations(mVibratorStateListenerMock);
+        // Trigger callbacks from controller.
+        mTestLooper.moveTimeForward(150);
+        mTestLooper.dispatchAll();
 
-        vibrate(service, VibrationEffect.createOneShot(10, VibrationEffect.DEFAULT_AMPLITUDE));
-        verifyNoMoreInteractions(mVibratorStateListenerMock);
+        InOrder inOrderVerifier = inOrder(mVibratorStateListenerMock);
+        // First notification done when listener is registered.
+        inOrderVerifier.verify(mVibratorStateListenerMock).onVibrating(eq(false));
+        inOrderVerifier.verify(mVibratorStateListenerMock).onVibrating(eq(true));
+        inOrderVerifier.verify(mVibratorStateListenerMock, atLeastOnce()).asBinder(); // unregister
+        inOrderVerifier.verifyNoMoreInteractions();
     }
 
     @Test
-    public void scale_withPrebaked_userIntensitySettingAsEffectStrength() {
+    public void scale_withPrebaked_userIntensitySettingAsEffectStrength() throws Exception {
         // Alarm vibration is always VIBRATION_INTENSITY_HIGH.
         setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_MEDIUM);
@@ -690,34 +554,34 @@
                 Vibrator.VIBRATION_INTENSITY_LOW);
         setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_OFF);
+        mVibratorProvider.setSupportedEffects(
+                VibrationEffect.EFFECT_CLICK,
+                VibrationEffect.EFFECT_TICK,
+                VibrationEffect.EFFECT_DOUBLE_CLICK,
+                VibrationEffect.EFFECT_HEAVY_CLICK);
         VibratorService service = createService();
 
-        vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK),
-                ALARM_ATTRS);
-        vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK),
+        vibrateAndWait(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), ALARM_ATTRS);
+        vibrateAndWait(service, VibrationEffect.get(VibrationEffect.EFFECT_TICK),
                 NOTIFICATION_ATTRS);
-        vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_DOUBLE_CLICK),
+        vibrateAndWait(service, VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK),
                 HAPTIC_FEEDBACK_ATTRS);
-        vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_HEAVY_CLICK),
-                RINGTONE_ATTRS);
+        vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK), RINGTONE_ATTRS);
 
-        verify(mNativeWrapperMock).perform(
-                eq((long) VibrationEffect.EFFECT_CLICK),
-                eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), anyLong());
-        verify(mNativeWrapperMock).perform(
-                eq((long) VibrationEffect.EFFECT_TICK),
-                eq((long) VibrationEffect.EFFECT_STRENGTH_MEDIUM), anyLong());
-        verify(mNativeWrapperMock).perform(
-                eq((long) VibrationEffect.EFFECT_DOUBLE_CLICK),
-                eq((long) VibrationEffect.EFFECT_STRENGTH_LIGHT), anyLong());
-        verify(mNativeWrapperMock, never()).perform(
-                eq((long) VibrationEffect.EFFECT_HEAVY_CLICK), anyLong(), anyLong());
+        List<Integer> playedStrengths = mVibratorProvider.getEffects().stream()
+                .map(VibrationEffect.Prebaked.class::cast)
+                .map(VibrationEffect.Prebaked::getEffectStrength)
+                .collect(Collectors.toList());
+        assertEquals(Arrays.asList(
+                VibrationEffect.EFFECT_STRENGTH_STRONG,
+                VibrationEffect.EFFECT_STRENGTH_MEDIUM,
+                VibrationEffect.EFFECT_STRENGTH_LIGHT),
+                playedStrengths);
     }
 
     @Test
     public void scale_withOneShotAndWaveform_usesScaleLevelOnAmplitude() throws Exception {
-        when(mVibratorMock.getDefaultNotificationVibrationIntensity())
-                .thenReturn(Vibrator.VIBRATION_INTENSITY_LOW);
+        mFakeVibrator.setDefaultNotificationVibrationIntensity(Vibrator.VIBRATION_INTENSITY_LOW);
         setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_HIGH);
         setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
@@ -725,33 +589,29 @@
         setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_OFF);
 
-        mockVibratorCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        mVibratorProvider.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         VibratorService service = createService();
 
-        vibrate(service, VibrationEffect.createOneShot(20, 100), ALARM_ATTRS);
-        vibrate(service, VibrationEffect.createOneShot(20, 100), NOTIFICATION_ATTRS);
-        vibrate(service, VibrationEffect.createOneShot(20, 255), RINGTONE_ATTRS);
-        vibrate(service, VibrationEffect.createWaveform(new long[] { 10 }, new int[] { 100 }, -1),
+        vibrateAndWait(service, VibrationEffect.createOneShot(20, 100), ALARM_ATTRS);
+        vibrateAndWait(service, VibrationEffect.createOneShot(20, 100), NOTIFICATION_ATTRS);
+        vibrateAndWait(service,
+                VibrationEffect.createWaveform(new long[]{10}, new int[]{100}, -1),
                 HAPTIC_FEEDBACK_ATTRS);
+        vibrate(service, VibrationEffect.createOneShot(20, 255), RINGTONE_ATTRS);
 
-        // Waveform effect runs on a separate thread.
-        Thread.sleep(15);
-
+        List<Integer> amplitudes = mVibratorProvider.getAmplitudes();
+        assertEquals(3, amplitudes.size());
         // Alarm vibration is never scaled.
-        verify(mNativeWrapperMock).setAmplitude(eq(100));
+        assertEquals(100, amplitudes.get(0).intValue());
         // Notification vibrations will be scaled with SCALE_VERY_HIGH.
-        verify(mNativeWrapperMock).setAmplitude(intThat(amplitude -> amplitude > 150));
+        assertTrue(amplitudes.get(1) > 150);
         // Haptic feedback vibrations will be scaled with SCALE_LOW.
-        verify(mNativeWrapperMock).setAmplitude(
-                intThat(amplitude -> amplitude < 100 && amplitude > 50));
-        // Ringtone vibration is off.
-        verify(mNativeWrapperMock, never()).setAmplitude(eq(255));
+        assertTrue(amplitudes.get(2) < 100 && amplitudes.get(2) > 50);
     }
 
     @Test
-    public void scale_withComposed_usesScaleLevelOnPrimitiveScaleValues() {
-        when(mVibratorMock.getDefaultNotificationVibrationIntensity())
-                .thenReturn(Vibrator.VIBRATION_INTENSITY_LOW);
+    public void scale_withComposed_usesScaleLevelOnPrimitiveScaleValues() throws Exception {
+        mFakeVibrator.setDefaultNotificationVibrationIntensity(Vibrator.VIBRATION_INTENSITY_LOW);
         setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_HIGH);
         setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
@@ -759,82 +619,72 @@
         setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_OFF);
 
-        mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+        mVibratorProvider.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
         VibratorService service = createService();
 
         VibrationEffect effect = VibrationEffect.startComposition()
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f)
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0.5f)
                 .compose();
-        ArgumentCaptor<VibrationEffect.Composition.PrimitiveEffect[]> primitivesCaptor =
-                ArgumentCaptor.forClass(VibrationEffect.Composition.PrimitiveEffect[].class);
 
-        vibrate(service, effect, ALARM_ATTRS);
-        vibrate(service, effect, NOTIFICATION_ATTRS);
-        vibrate(service, effect, HAPTIC_FEEDBACK_ATTRS);
+        vibrateAndWait(service, effect, ALARM_ATTRS);
+        vibrateAndWait(service, effect, NOTIFICATION_ATTRS);
+        vibrateAndWait(service, effect, HAPTIC_FEEDBACK_ATTRS);
         vibrate(service, effect, RINGTONE_ATTRS);
 
-        // Ringtone vibration is off, so only the other 3 are propagated to native.
-        verify(mNativeWrapperMock, times(3)).compose(
-                primitivesCaptor.capture(), anyLong());
+        List<VibrationEffect.Composition.PrimitiveEffect> primitives =
+                mVibratorProvider.getEffects().stream()
+                        .map(VibrationEffect.Composed.class::cast)
+                        .map(VibrationEffect.Composed::getPrimitiveEffects)
+                        .flatMap(List::stream)
+                        .collect(Collectors.toList());
 
-        List<VibrationEffect.Composition.PrimitiveEffect[]> values =
-                primitivesCaptor.getAllValues();
+        // Ringtone vibration is off, so only the other 3 are propagated to native.
+        assertEquals(6, primitives.size());
 
         // Alarm vibration is never scaled.
-        assertEquals(1f, values.get(0)[0].scale, /* delta= */ 1e-2);
-        assertEquals(0.5f, values.get(0)[1].scale, /* delta= */ 1e-2);
+        assertEquals(1f, primitives.get(0).scale, /* delta= */ 1e-2);
+        assertEquals(0.5f, primitives.get(1).scale, /* delta= */ 1e-2);
 
         // Notification vibrations will be scaled with SCALE_VERY_HIGH.
-        assertEquals(1f, values.get(1)[0].scale, /* delta= */ 1e-2);
-        assertTrue(0.7 < values.get(1)[1].scale);
+        assertEquals(1f, primitives.get(2).scale, /* delta= */ 1e-2);
+        assertTrue(0.7 < primitives.get(3).scale);
 
         // Haptic feedback vibrations will be scaled with SCALE_LOW.
-        assertTrue(0.5 < values.get(2)[0].scale);
-        assertTrue(0.5 > values.get(2)[1].scale);
-    }
-
-    private void vibrate(VibratorService service, VibrationEffect effect) {
-        vibrate(service, effect, ALARM_ATTRS);
+        assertTrue(0.5 < primitives.get(4).scale);
+        assertTrue(0.5 > primitives.get(5).scale);
     }
 
     private void vibrate(VibratorService service, VibrationEffect effect,
-            VibrationAttributes attributes) {
-        service.vibrate(UID, PACKAGE_NAME, effect, attributes, "some reason", service);
+            VibrationAttributes attrs) {
+        service.vibrate(UID, PACKAGE_NAME, effect, attrs, "some reason", service);
     }
 
-    private int vibrateAndMeasure(
-            VibratorService service, VibrationEffect effect, long timeoutSecs) throws Exception {
-        AtomicLong startTime = new AtomicLong(0);
-        AtomicLong endTime = new AtomicLong(0);
+    private void vibrateAndWait(VibratorService service, VibrationEffect effect,
+            VibrationAttributes attrs) throws Exception {
         CountDownLatch startedCount = new CountDownLatch(1);
         CountDownLatch finishedCount = new CountDownLatch(1);
         service.registerVibratorStateListener(new IVibratorStateListener() {
             @Override
-            public void onVibrating(boolean vibrating) throws RemoteException {
+            public void onVibrating(boolean vibrating) {
                 if (vibrating) {
-                    startTime.set(SystemClock.uptimeMillis());
                     startedCount.countDown();
                 } else if (startedCount.getCount() == 0) {
-                    endTime.set(SystemClock.uptimeMillis());
                     finishedCount.countDown();
                 }
             }
 
             @Override
             public IBinder asBinder() {
-                return mVibratorStateListenerBinderMock;
+                return mock(IBinder.class);
             }
         });
 
-        vibrate(service, effect);
-
-        assertTrue(finishedCount.await(timeoutSecs, TimeUnit.SECONDS));
-        return (int) (endTime.get() - startTime.get());
-    }
-
-    private void mockVibratorCapabilities(int capabilities) {
-        when(mNativeWrapperMock.getCapabilities()).thenReturn((long) capabilities);
+        mTestLooper.startAutoDispatch();
+        service.vibrate(UID, PACKAGE_NAME, effect, attrs, "some reason", service);
+        assertTrue(startedCount.await(1, TimeUnit.SECONDS));
+        assertTrue(finishedCount.await(1, TimeUnit.SECONDS));
+        mTestLooper.stopAutoDispatchAndIgnoreExceptions();
     }
 
     private InputDevice createInputDeviceWithVibrator(int id) {
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index 74c6a7e..784718b 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -53,7 +53,9 @@
 import static org.mockito.Mockito.validateMockitoUsage;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
 
+import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.IUserSwitchObserver;
@@ -71,6 +73,7 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.os.storage.IStorageManager;
 import android.platform.test.annotations.Presubmit;
 import android.util.Log;
@@ -161,7 +164,7 @@
             // All UserController params are set to default.
             mUserController = new UserController(mInjector);
             setUpUser(TEST_USER_ID, NO_USERINFO_FLAGS);
-            setUpUser(TEST_PRE_CREATED_USER_ID, NO_USERINFO_FLAGS, /* preCreated=*/ true);
+            setUpUser(TEST_PRE_CREATED_USER_ID, NO_USERINFO_FLAGS, /* preCreated=*/ true, null);
         });
     }
 
@@ -549,19 +552,75 @@
                 /* keyEvictedCallback= */ mKeyEvictedCallback, /* expectLocking= */ true);
     }
 
+    @Test
+    public void testStartProfile_fullUserFails() {
+        setUpUser(TEST_USER_ID1, 0);
+        assertThrows(IllegalArgumentException.class,
+                () -> mUserController.startProfile(TEST_USER_ID1));
+    }
+
+    @Test
+    public void testStopProfile_fullUserFails() throws Exception {
+        setUpAndStartUserInBackground(TEST_USER_ID1);
+        assertThrows(IllegalArgumentException.class,
+                () -> mUserController.stopProfile(TEST_USER_ID1));
+    }
+
+    @Test
+    public void testStartProfile_disabledProfileFails() {
+        setUpUser(TEST_USER_ID1, UserInfo.FLAG_PROFILE | UserInfo.FLAG_DISABLED, /* preCreated= */
+                false, UserManager.USER_TYPE_PROFILE_MANAGED);
+        assertThat(mUserController.startProfile(TEST_USER_ID1)).isFalse();
+    }
+
+    @Test
+    public void testStartProfile() throws Exception {
+        setUpAndStartProfileInBackground(TEST_USER_ID1);
+        startBackgroundUserAssertions();
+    }
+
+    @Test
+    public void testStopProfile() throws Exception {
+        setUpAndStartProfileInBackground(TEST_USER_ID1);
+        assertProfileLockedOrUnlockedAfterStopping(TEST_USER_ID1, /* expectLocking= */ true);
+    }
+
     private void setUpAndStartUserInBackground(int userId) throws Exception {
         setUpUser(userId, 0);
         mUserController.startUser(userId, /* foreground= */ false);
         verify(mInjector.mStorageManagerMock, times(1))
-                .unlockUserKey(TEST_USER_ID, 0, null, null);
+                .unlockUserKey(userId, /* serialNumber= */ 0, /* token= */ null, /* secret= */
+                        null);
+        mUserStates.put(userId, mUserController.getStartedUserState(userId));
+    }
+
+    private void setUpAndStartProfileInBackground(int userId) throws Exception {
+        setUpUser(userId, UserInfo.FLAG_PROFILE, false, UserManager.USER_TYPE_PROFILE_MANAGED);
+        assertThat(mUserController.startProfile(userId)).isTrue();
+
+        verify(mInjector.mStorageManagerMock, times(1))
+                .unlockUserKey(userId, /* serialNumber= */ 0, /* token= */ null, /* secret= */
+                        null);
         mUserStates.put(userId, mUserController.getStartedUserState(userId));
     }
 
     private void assertUserLockedOrUnlockedAfterStopping(int userId, boolean delayedLocking,
-            KeyEvictedCallback keyEvictedCallback, boolean expectLocking)  throws Exception {
+            KeyEvictedCallback keyEvictedCallback, boolean expectLocking) throws Exception {
         int r = mUserController.stopUser(userId, /* force= */ true, /* delayedLocking= */
                 delayedLocking, null, keyEvictedCallback);
         assertThat(r).isEqualTo(ActivityManager.USER_OP_SUCCESS);
+        assertUserLockedOrUnlockedState(userId, delayedLocking, expectLocking);
+    }
+
+    private void assertProfileLockedOrUnlockedAfterStopping(int userId, boolean expectLocking)
+            throws Exception {
+        boolean profileStopped = mUserController.stopProfile(userId);
+        assertThat(profileStopped).isTrue();
+        assertUserLockedOrUnlockedState(userId, /* delayedLocking= */ false, expectLocking);
+    }
+
+    private void assertUserLockedOrUnlockedState(int userId, boolean delayedLocking,
+            boolean expectLocking) throws InterruptedException, RemoteException {
         // fake all interim steps
         UserState ussUser = mUserStates.get(userId);
         ussUser.setState(UserState.STATE_SHUTDOWN);
@@ -594,11 +653,16 @@
     }
 
     private void setUpUser(@UserIdInt int userId, @UserInfoFlag int flags) {
-        setUpUser(userId, flags, /* preCreated= */ false);
+        setUpUser(userId, flags, /* preCreated= */ false, /* userType */ null);
     }
 
-    private void setUpUser(@UserIdInt int userId, @UserInfoFlag int flags, boolean preCreated) {
-        UserInfo userInfo = new UserInfo(userId, "User" + userId, flags);
+    private void setUpUser(@UserIdInt int userId, @UserInfoFlag int flags, boolean preCreated,
+            @Nullable String userType) {
+        if (userType == null) {
+            userType = UserInfo.getDefaultUserType(flags);
+        }
+        UserInfo userInfo = new UserInfo(userId, "User" + userId, /* iconPath= */ null, flags,
+                userType);
         userInfo.preCreated = preCreated;
         when(mInjector.mUserManagerMock.getUserInfo(eq(userId))).thenReturn(userInfo);
         when(mInjector.mUserManagerMock.isPreCreated(userId)).thenReturn(preCreated);
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 009cb0b..6366155 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
@@ -1230,14 +1230,14 @@
 
     @Test
     public void testRewriteSearchResultProto() throws Exception {
-        final String database =
+        final String prefix =
                 "com.package.foo"
                         + AppSearchImpl.PACKAGE_DELIMITER
                         + "databaseName"
                         + AppSearchImpl.DATABASE_DELIMITER;
         final String uri = "uri";
-        final String namespace = database + "namespace";
-        final String schemaType = database + "schema";
+        final String namespace = prefix + "namespace";
+        final String schemaType = prefix + "schema";
 
         // Building the SearchResult received from query.
         DocumentProto documentProto =
@@ -1257,6 +1257,7 @@
                 AppSearchImpl.rewriteSearchResultProto(searchResultProto);
         for (SearchResult result : searchResultPage.getResults()) {
             assertThat(result.getPackageName()).isEqualTo("com.package.foo");
+            assertThat(result.getDatabaseName()).isEqualTo("databaseName");
             assertThat(result.getDocument())
                     .isEqualTo(
                             GenericDocumentToProtoConverter.toGenericDocument(
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java
index a3f0f6b..97daea3 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java
@@ -86,7 +86,9 @@
         // Making ResultReader and getting Snippet values.
         SearchResultPage searchResultPage =
                 SearchResultToProtoConverter.toSearchResultPage(
-                        searchResultProto, Collections.singletonList("packageName"));
+                        searchResultProto,
+                        Collections.singletonList("packageName"),
+                        Collections.singletonList("databaseName"));
         for (SearchResult result : searchResultPage.getResults()) {
             SearchResult.MatchInfo match = result.getMatches().get(0);
             assertThat(match.getPropertyPath()).isEqualTo(propertyKeyString);
@@ -135,7 +137,9 @@
 
         SearchResultPage searchResultPage =
                 SearchResultToProtoConverter.toSearchResultPage(
-                        searchResultProto, Collections.singletonList("packageName"));
+                        searchResultProto,
+                        Collections.singletonList("packageName"),
+                        Collections.singletonList("databaseName"));
         for (SearchResult result : searchResultPage.getResults()) {
             assertThat(result.getMatches()).isEmpty();
         }
@@ -201,7 +205,9 @@
         // Making ResultReader and getting Snippet values.
         SearchResultPage searchResultPage =
                 SearchResultToProtoConverter.toSearchResultPage(
-                        searchResultProto, Collections.singletonList("packageName"));
+                        searchResultProto,
+                        Collections.singletonList("packageName"),
+                        Collections.singletonList("databaseName"));
         for (SearchResult result : searchResultPage.getResults()) {
 
             SearchResult.MatchInfo match1 = result.getMatches().get(0);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/InvalidationTrackerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/InvalidationTrackerTest.java
index 340a1d9..bb2b1c2 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/InvalidationTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/InvalidationTrackerTest.java
@@ -22,7 +22,9 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
+import android.content.Context;
 import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.BiometricManager.Authenticators;
 import android.hardware.biometrics.IBiometricAuthenticator;
@@ -44,21 +46,25 @@
     @Test
     public void testCallbackReceived_whenAllStrongSensorsInvalidated() throws Exception {
         final IBiometricAuthenticator authenticator1 = mock(IBiometricAuthenticator.class);
+        when(authenticator1.hasEnrolledTemplates(anyInt(), any())).thenReturn(true);
         final TestSensor sensor1 = new TestSensor(0 /* id */,
                 BiometricAuthenticator.TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG,
                 authenticator1);
 
         final IBiometricAuthenticator authenticator2 = mock(IBiometricAuthenticator.class);
+        when(authenticator2.hasEnrolledTemplates(anyInt(), any())).thenReturn(true);
         final TestSensor sensor2 = new TestSensor(1 /* id */,
                 BiometricAuthenticator.TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG,
                 authenticator2);
 
         final IBiometricAuthenticator authenticator3 = mock(IBiometricAuthenticator.class);
+        when(authenticator3.hasEnrolledTemplates(anyInt(), any())).thenReturn(true);
         final TestSensor sensor3 = new TestSensor(2 /* id */,
                 BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG,
                 authenticator3);
 
         final IBiometricAuthenticator authenticator4 = mock(IBiometricAuthenticator.class);
+        when(authenticator4.hasEnrolledTemplates(anyInt(), any())).thenReturn(true);
         final TestSensor sensor4 = new TestSensor(3 /* id */,
                 BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_WEAK,
                 authenticator4);
@@ -71,7 +77,8 @@
 
         final IInvalidationCallback callback = mock(IInvalidationCallback.class);
         final InvalidationTracker tracker =
-                InvalidationTracker.start(sensors, 0 /* userId */, 0 /* fromSensorId */, callback);
+                InvalidationTracker.start(mock(Context.class), sensors, 0 /* userId */,
+                        0 /* fromSensorId */, callback);
 
         // The sensor which the request originated from should not be requested to invalidate
         // its authenticatorId.
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index 600f681..cc4541b 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -71,11 +71,11 @@
 
     @Test
     public void testClientDuplicateFinish_ignoredBySchedulerAndDoesNotCrash() {
-        final BaseClientMonitor.LazyDaemon<Object> nonNullDaemon = () -> mock(Object.class);
+        final HalClientMonitor.LazyDaemon<Object> nonNullDaemon = () -> mock(Object.class);
 
-        final BaseClientMonitor<Object> client1 =
+        final HalClientMonitor<Object> client1 =
                 new TestClientMonitor(mContext, mToken, nonNullDaemon);
-        final BaseClientMonitor<Object> client2 =
+        final HalClientMonitor<Object> client2 =
                 new TestClientMonitor(mContext, mToken, nonNullDaemon);
         mScheduler.scheduleClientMonitor(client1);
         mScheduler.scheduleClientMonitor(client2);
@@ -89,8 +89,8 @@
         // Even if second client has a non-null daemon, it needs to be canceled.
         Object daemon2 = mock(Object.class);
 
-        final BaseClientMonitor.LazyDaemon<Object> lazyDaemon1 = () -> null;
-        final BaseClientMonitor.LazyDaemon<Object> lazyDaemon2 = () -> daemon2;
+        final HalClientMonitor.LazyDaemon<Object> lazyDaemon1 = () -> null;
+        final HalClientMonitor.LazyDaemon<Object> lazyDaemon2 = () -> daemon2;
 
         final TestClientMonitor client1 = new TestClientMonitor(mContext, mToken, lazyDaemon1);
         final TestClientMonitor client2 = new TestClientMonitor(mContext, mToken, lazyDaemon2);
@@ -126,8 +126,8 @@
         // Second non-BiometricPrompt client has a valid daemon
         final Object daemon2 = mock(Object.class);
 
-        final BaseClientMonitor.LazyDaemon<Object> lazyDaemon1 = () -> null;
-        final BaseClientMonitor.LazyDaemon<Object> lazyDaemon2 = () -> daemon2;
+        final HalClientMonitor.LazyDaemon<Object> lazyDaemon1 = () -> null;
+        final HalClientMonitor.LazyDaemon<Object> lazyDaemon2 = () -> daemon2;
 
         final ClientMonitorCallbackConverter listener1 = mock(ClientMonitorCallbackConverter.class);
 
@@ -167,7 +167,7 @@
 
     @Test
     public void testCancelNotInvoked_whenOperationWaitingForCookie() {
-        final BaseClientMonitor.LazyDaemon<Object> lazyDaemon1 = () -> mock(Object.class);
+        final HalClientMonitor.LazyDaemon<Object> lazyDaemon1 = () -> mock(Object.class);
         final BiometricPromptClientMonitor client1 = new BiometricPromptClientMonitor(mContext,
                 mToken, lazyDaemon1, mock(ClientMonitorCallbackConverter.class));
         final BaseClientMonitor.Callback callback1 = mock(BaseClientMonitor.Callback.class);
@@ -207,7 +207,7 @@
         }
     }
 
-    private static class TestClientMonitor extends BaseClientMonitor<Object> {
+    private static class TestClientMonitor extends HalClientMonitor<Object> {
         private boolean mUnableToStart;
         private boolean mStarted;
 
@@ -223,7 +223,6 @@
                     0 /* statsAction */, 0 /* statsClient */);
         }
 
-
         @Override
         public void unableToStart() {
             assertFalse(mUnableToStart);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceProviderTest.java
index ffd4378..04a7122 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceProviderTest.java
@@ -33,6 +33,7 @@
 
 import com.android.server.biometrics.sensors.BaseClientMonitor;
 import com.android.server.biometrics.sensors.BiometricScheduler;
+import com.android.server.biometrics.sensors.HalClientMonitor;
 import com.android.server.biometrics.sensors.LockoutResetDispatcher;
 
 import org.junit.Before;
@@ -94,7 +95,7 @@
             final BiometricScheduler scheduler =
                     mFaceProvider.mSensors.get(prop.commonProps.sensorId).getScheduler();
             for (int i = 0; i < numFakeOperations; i++) {
-                final BaseClientMonitor testMonitor = mock(BaseClientMonitor.class);
+                final HalClientMonitor testMonitor = mock(HalClientMonitor.class);
                 when(testMonitor.getFreshDaemon()).thenReturn(new Object());
                 scheduler.scheduleClientMonitor(testMonitor);
             }
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java
index 99aab5c..392535e 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java
@@ -16,6 +16,8 @@
 
 package com.android.server.biometrics.sensors.face.hidl;
 
+import static junit.framework.Assert.assertEquals;
+
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -76,6 +78,12 @@
     }
 
     @Test
+    public void getAuthenticatorId_doesNotCrashWhenIdNotFound() {
+        assertEquals(0, mFace10.getAuthenticatorId(0 /* sensorId */, 111 /* userId */));
+        waitForIdle();
+    }
+
+    @Test
     public void scheduleRevokeChallenge_doesNotCrash() {
         mFace10.scheduleRevokeChallenge(0 /* sensorId */, 0 /* userId */, mBinder, TAG,
                 0 /* challenge */);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
index 175c4da..d149880 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
@@ -33,6 +33,7 @@
 
 import com.android.server.biometrics.sensors.BaseClientMonitor;
 import com.android.server.biometrics.sensors.BiometricScheduler;
+import com.android.server.biometrics.sensors.HalClientMonitor;
 import com.android.server.biometrics.sensors.LockoutResetDispatcher;
 import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
 
@@ -97,7 +98,7 @@
             final BiometricScheduler scheduler =
                     mFingerprintProvider.mSensors.get(prop.commonProps.sensorId).getScheduler();
             for (int i = 0; i < numFakeOperations; i++) {
-                final BaseClientMonitor testMonitor = mock(BaseClientMonitor.class);
+                final HalClientMonitor testMonitor = mock(HalClientMonitor.class);
                 when(testMonitor.getFreshDaemon()).thenReturn(new Object());
                 scheduler.scheduleClientMonitor(testMonitor);
             }
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java
index b2aeb33..61cc8e6 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java
@@ -16,6 +16,8 @@
 
 package com.android.server.biometrics.sensors.fingerprint.hidl;
 
+import static junit.framework.Assert.assertEquals;
+
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -85,6 +87,12 @@
     }
 
     @Test
+    public void getAuthenticatorId_doesNotCrashWhenIdNotFound() {
+        assertEquals(0, mFingerprint21.getAuthenticatorId(0 /* sensorId */, 111 /* userId */));
+        waitForIdle();
+    }
+
+    @Test
     public void halServiceDied_resetsScheduler() {
         // It's difficult to test the linkToDeath --> serviceDied path, so let's just invoke
         // serviceDied directly.
diff --git a/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java b/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
new file mode 100644
index 0000000..0cf0af3
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.graphics.fonts;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.content.Context;
+import android.os.FileUtils;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Map;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public final class UpdatableFontDirTest {
+
+    /**
+     * A {@link UpdatableFontDir.FontFileParser} for testing. Instead of using real font files,
+     * this test uses fake font files. A fake font file has its version as its file content.
+     */
+    private static class FakeFontFileParser implements UpdatableFontDir.FontFileParser {
+        @Override
+        public long getVersion(File file) throws IOException {
+            return Long.parseLong(FileUtils.readTextFile(file, 100, ""));
+        }
+    }
+
+    private File mCacheDir;
+    private File mUpdatableFontFilesDir;
+
+    @SuppressWarnings("ResultOfMethodCallIgnored")
+    @Before
+    public void setUp() {
+        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        mCacheDir = new File(context.getCacheDir(), "UpdatableFontDirTest");
+        FileUtils.deleteContentsAndDir(mCacheDir);
+        mCacheDir.mkdirs();
+        mUpdatableFontFilesDir = new File(mCacheDir, "updatable_fonts");
+        mUpdatableFontFilesDir.mkdir();
+    }
+
+    @After
+    public void tearDown() {
+        FileUtils.deleteContentsAndDir(mCacheDir);
+    }
+
+    @Test
+    public void construct() throws Exception {
+        FakeFontFileParser parser = new FakeFontFileParser();
+        UpdatableFontDir dirForPreparation = new UpdatableFontDir(mUpdatableFontFilesDir, parser);
+        installFontFile(dirForPreparation, "foo.ttf", "1");
+        installFontFile(dirForPreparation, "bar.ttf", "2");
+        installFontFile(dirForPreparation, "foo.ttf", "3");
+        installFontFile(dirForPreparation, "bar.ttf", "4");
+        // Four font dirs are created.
+        assertThat(mUpdatableFontFilesDir.list()).hasLength(4);
+
+        UpdatableFontDir dir = new UpdatableFontDir(mUpdatableFontFilesDir, parser);
+        assertThat(dir.getFontFileMap()).containsKey("foo.ttf");
+        assertThat(parser.getVersion(dir.getFontFileMap().get("foo.ttf"))).isEqualTo(3);
+        assertThat(dir.getFontFileMap()).containsKey("bar.ttf");
+        assertThat(parser.getVersion(dir.getFontFileMap().get("bar.ttf"))).isEqualTo(4);
+        // Outdated font dir should be deleted.
+        assertThat(mUpdatableFontFilesDir.list()).hasLength(2);
+    }
+
+    @Test
+    public void construct_empty() {
+        FakeFontFileParser parser = new FakeFontFileParser();
+        UpdatableFontDir dir = new UpdatableFontDir(mUpdatableFontFilesDir, parser);
+        assertThat(dir.getFontFileMap()).isEmpty();
+    }
+
+    @Test
+    public void installFontFile() throws Exception {
+        FakeFontFileParser parser = new FakeFontFileParser();
+        UpdatableFontDir dir = new UpdatableFontDir(mUpdatableFontFilesDir, parser);
+
+        installFontFile(dir, "test.ttf", "1");
+        assertThat(dir.getFontFileMap()).containsKey("test.ttf");
+        assertThat(parser.getVersion(dir.getFontFileMap().get("test.ttf"))).isEqualTo(1);
+    }
+
+    @Test
+    public void installFontFile_upgrade() throws Exception {
+        FakeFontFileParser parser = new FakeFontFileParser();
+        UpdatableFontDir dir = new UpdatableFontDir(mUpdatableFontFilesDir, parser);
+
+        installFontFile(dir, "test.ttf", "1");
+        Map<String, File> mapBeforeUpgrade = dir.getFontFileMap();
+        installFontFile(dir, "test.ttf", "2");
+        assertThat(dir.getFontFileMap()).containsKey("test.ttf");
+        assertThat(parser.getVersion(dir.getFontFileMap().get("test.ttf"))).isEqualTo(2);
+        assertThat(mapBeforeUpgrade).containsKey("test.ttf");
+        assertWithMessage("Older fonts should not be deleted until next loadFontFileMap")
+                .that(parser.getVersion(mapBeforeUpgrade.get("test.ttf"))).isEqualTo(1);
+    }
+
+    @Test
+    public void installFontFile_downgrade() throws Exception {
+        FakeFontFileParser parser = new FakeFontFileParser();
+        UpdatableFontDir dir = new UpdatableFontDir(mUpdatableFontFilesDir, parser);
+
+        installFontFile(dir, "test.ttf", "2");
+        installFontFile(dir, "test.ttf", "1");
+        assertThat(dir.getFontFileMap()).containsKey("test.ttf");
+        assertWithMessage("Font should not be downgraded to an older version")
+                .that(parser.getVersion(dir.getFontFileMap().get("test.ttf"))).isEqualTo(2);
+    }
+
+    @Test
+    public void installFontFile_multiple() throws Exception {
+        FakeFontFileParser parser = new FakeFontFileParser();
+        UpdatableFontDir dir = new UpdatableFontDir(mUpdatableFontFilesDir, parser);
+
+        installFontFile(dir, "foo.ttf", "1");
+        installFontFile(dir, "bar.ttf", "2");
+        assertThat(dir.getFontFileMap()).containsKey("foo.ttf");
+        assertThat(parser.getVersion(dir.getFontFileMap().get("foo.ttf"))).isEqualTo(1);
+        assertThat(dir.getFontFileMap()).containsKey("bar.ttf");
+        assertThat(parser.getVersion(dir.getFontFileMap().get("bar.ttf"))).isEqualTo(2);
+    }
+
+    private void installFontFile(UpdatableFontDir dir, String name, String content)
+            throws IOException {
+        File file = File.createTempFile(name, "", mCacheDir);
+        FileUtils.stringToFile(file, content);
+        try (FileInputStream in = new FileInputStream(file)) {
+            dir.installFontFile(name, in.getFD());
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java b/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java
index b7d9a56..a7b32ac 100644
--- a/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java
@@ -41,6 +41,7 @@
 import android.util.Log;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
@@ -134,6 +135,7 @@
         assertTrue("Job did not start after scheduling", awaitJobStart(DEFAULT_WAIT_TIMEOUT));
     }
 
+    @FlakyTest
     @Test
     public void testPowerExemption() throws Exception {
         scheduleAndAssertJobStarted();
diff --git a/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
index 5f65440..a5039fb 100644
--- a/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
@@ -82,6 +82,7 @@
     private PowerStatsLogger mPowerStatsLogger;
 
     private final PowerStatsService.Injector mInjector = new PowerStatsService.Injector() {
+        private TestPowerStatsHALWrapper mTestPowerStatsHALWrapper = new TestPowerStatsHALWrapper();
         @Override
         File createDataStoragePath() {
             mDataStorageDir = null;
@@ -111,8 +112,8 @@
         }
 
         @Override
-        IPowerStatsHALWrapper createPowerStatsHALWrapperImpl() {
-            return new TestPowerStatsHALWrapper();
+        IPowerStatsHALWrapper getPowerStatsHALWrapperImpl() {
+            return mTestPowerStatsHALWrapper;
         }
 
         @Override
diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
index 3858370..aadab6e 100644
--- a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
@@ -25,6 +25,7 @@
 import android.media.tv.ITvInputManager;
 import android.media.tv.TvInputManager;
 import android.media.tv.TvInputService;
+import android.media.tv.tuner.TunerFrontendInfo;
 import android.media.tv.tuner.frontend.FrontendSettings;
 import android.media.tv.tunerresourcemanager.CasSessionRequest;
 import android.media.tv.tunerresourcemanager.IResourcesReclaimListener;
@@ -32,7 +33,6 @@
 import android.media.tv.tunerresourcemanager.TunerCiCamRequest;
 import android.media.tv.tunerresourcemanager.TunerDemuxRequest;
 import android.media.tv.tunerresourcemanager.TunerDescramblerRequest;
-import android.media.tv.tunerresourcemanager.TunerFrontendInfo;
 import android.media.tv.tunerresourcemanager.TunerFrontendRequest;
 import android.media.tv.tunerresourcemanager.TunerLnbRequest;
 import android.media.tv.tunerresourcemanager.TunerResourceManager;
@@ -88,7 +88,7 @@
                 }
 
                 return actual.getHandle() == expected.handle
-                        && actual.getType() == expected.frontendType
+                        && actual.getType() == expected.type
                         && actual.getExclusiveGroupId() == expected.exclusiveGroupId;
             },  "is correctly configured from ");
 
@@ -1156,7 +1156,7 @@
             int handle, int frontendType, int exclusiveGroupId) {
         TunerFrontendInfo info = new TunerFrontendInfo();
         info.handle = handle;
-        info.frontendType = frontendType;
+        info.type = frontendType;
         info.exclusiveGroupId = exclusiveGroupId;
         return info;
     }
diff --git a/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java b/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java
index 7c65dc0..b40d59c 100644
--- a/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java
@@ -254,6 +254,8 @@
             tester.verify(15, "Tick after snapshot");
             // Verify that the snapshot is sealed
             verifySealed(name, ()->arraySnap.put(INDEX_A, leafA));
+            assertTrue(!array.isSealed());
+            assertTrue(arraySnap.isSealed());
         }
         // Recreate the snapshot since the test corrupted it.
         {
@@ -355,6 +357,8 @@
             tester.verify(16, "Tick after snapshot");
             // Verify that the array snapshot is sealed
             verifySealed(name, ()->arraySnap.add(leafB));
+            assertTrue(!array.isSealed());
+            assertTrue(arraySnap.isSealed());
         }
         // Recreate the snapshot since the test corrupted it.
         {
@@ -467,6 +471,8 @@
             tester.verify(20, "Tick after snapshot");
             // Verify that the array snapshot is sealed
             verifySealed(name, ()->arraySnap.add(indexA, leafB));
+            assertTrue(!array.isSealed());
+            assertTrue(arraySnap.isSealed());
         }
         // Recreate the snapshot since the test corrupted it.
         {
@@ -586,6 +592,8 @@
             tester.verify(23, "Tick after snapshot");
             // Verify that the array snapshot is sealed
             verifySealed(name, ()->arraySnap.put(INDEX_A, leafB));
+            assertTrue(!array.isSealed());
+            assertTrue(arraySnap.isSealed());
         }
         // Recreate the snapshot since the test corrupted it.
         {
@@ -649,6 +657,8 @@
             tester.verify(6, "Tick after snapshot");
             // Verify that the array is sealed
             verifySealed(name, ()->arraySnap.put(INDEX_D, false));
+            assertTrue(!array.isSealed());
+            assertTrue(arraySnap.isSealed());
         }
         // Verify copy-in/out
         {
@@ -705,6 +715,8 @@
             tester.verify(6, "Tick after snapshot");
             // Verify that the array is sealed
             verifySealed(name, ()->arraySnap.put(INDEX_D, 10));
+            assertTrue(!array.isSealed());
+            assertTrue(arraySnap.isSealed());
         }
         // Verify copy-in/out
         {
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/FakeVibrator.java b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibrator.java
new file mode 100644
index 0000000..72c40ea
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibrator.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vibrator;
+
+import android.os.VibrationAttributes;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
+
+import androidx.annotation.NonNull;
+
+/** Fake implementation of {@link Vibrator} for service tests. */
+public final class FakeVibrator extends Vibrator {
+
+    private int mDefaultHapticFeedbackIntensity = Vibrator.VIBRATION_INTENSITY_MEDIUM;
+    private int mDefaultNotificationIntensity = Vibrator.VIBRATION_INTENSITY_MEDIUM;
+    private int mDefaultRingIntensity = Vibrator.VIBRATION_INTENSITY_MEDIUM;
+
+    @Override
+    public int getDefaultHapticFeedbackIntensity() {
+        return mDefaultHapticFeedbackIntensity;
+    }
+
+    @Override
+    public int getDefaultNotificationVibrationIntensity() {
+        return mDefaultNotificationIntensity;
+    }
+
+    @Override
+    public int getDefaultRingVibrationIntensity() {
+        return mDefaultRingIntensity;
+    }
+
+    public void setDefaultHapticFeedbackIntensity(
+            @VibrationIntensity int defaultHapticFeedbackIntensity) {
+        mDefaultHapticFeedbackIntensity = defaultHapticFeedbackIntensity;
+    }
+
+    public void setDefaultNotificationVibrationIntensity(
+            @VibrationIntensity int defaultNotificationIntensity) {
+        mDefaultNotificationIntensity = defaultNotificationIntensity;
+    }
+
+    public void setDefaultRingVibrationIntensity(@VibrationIntensity int defaultRingIntensity) {
+        mDefaultRingIntensity = defaultRingIntensity;
+    }
+
+    @Override
+    public boolean hasVibrator() {
+        return true;
+    }
+
+    @Override
+    public boolean hasAmplitudeControl() {
+        return true;
+    }
+
+    @Override
+    public void vibrate(int uid, String opPkg, @NonNull VibrationEffect vibe, String reason,
+            @NonNull VibrationAttributes attributes) {
+    }
+
+    @Override
+    public void cancel() {
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java
new file mode 100644
index 0000000..f562c16
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vibrator;
+
+import android.annotation.Nullable;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.VibrationEffect;
+
+import com.android.server.vibrator.VibratorController.OnVibrationCompleteListener;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Provides {@link VibratorController} with controlled vibrator hardware capabilities and
+ * interactions.
+ */
+public final class FakeVibratorControllerProvider {
+
+    private static final int EFFECT_DURATION = 20;
+
+    private final Map<Long, VibrationEffect.Prebaked> mEnabledAlwaysOnEffects = new HashMap<>();
+    private final List<VibrationEffect> mEffects = new ArrayList<>();
+    private final List<Integer> mAmplitudes = new ArrayList<>();
+    private final Handler mHandler;
+    private final FakeNativeWrapper mNativeWrapper;
+
+    private boolean mIsAvailable = true;
+    private long mLatency;
+
+    private int mCapabilities;
+    private int[] mSupportedEffects;
+    private int[] mSupportedPrimitives;
+
+    private final class FakeNativeWrapper extends VibratorController.NativeWrapper {
+        public int vibratorId;
+        public OnVibrationCompleteListener listener;
+        public boolean isInitialized;
+
+        public void init(int vibratorId, OnVibrationCompleteListener listener) {
+            isInitialized = true;
+            this.vibratorId = vibratorId;
+            this.listener = listener;
+        }
+
+        public boolean isAvailable() {
+            return mIsAvailable;
+        }
+
+        public void on(long milliseconds, long vibrationId) {
+            VibrationEffect effect = VibrationEffect.createOneShot(
+                    milliseconds, VibrationEffect.DEFAULT_AMPLITUDE);
+            mEffects.add(effect);
+            applyLatency();
+            scheduleListener(milliseconds, vibrationId);
+        }
+
+        public void off() {
+        }
+
+        public void setAmplitude(int amplitude) {
+            mAmplitudes.add(amplitude);
+            applyLatency();
+        }
+
+        public int[] getSupportedEffects() {
+            return mSupportedEffects;
+        }
+
+        public int[] getSupportedPrimitives() {
+            return mSupportedPrimitives;
+        }
+
+        public long perform(long effect, long strength, long vibrationId) {
+            if (mSupportedEffects == null
+                    || Arrays.binarySearch(mSupportedEffects, (int) effect) < 0) {
+                return 0;
+            }
+            mEffects.add(new VibrationEffect.Prebaked((int) effect, false, (int) strength));
+            applyLatency();
+            scheduleListener(EFFECT_DURATION, vibrationId);
+            return EFFECT_DURATION;
+        }
+
+        public void compose(VibrationEffect.Composition.PrimitiveEffect[] effect,
+                long vibrationId) {
+            VibrationEffect.Composed composed = new VibrationEffect.Composed(Arrays.asList(effect));
+            mEffects.add(composed);
+            applyLatency();
+            long duration = EFFECT_DURATION * effect.length;
+            for (VibrationEffect.Composition.PrimitiveEffect e : effect) {
+                duration += e.delay;
+            }
+            scheduleListener(duration, vibrationId);
+        }
+
+        public void setExternalControl(boolean enabled) {
+        }
+
+        public long getCapabilities() {
+            return mCapabilities;
+        }
+
+        public void alwaysOnEnable(long id, long effect, long strength) {
+            VibrationEffect.Prebaked prebaked = new VibrationEffect.Prebaked((int) effect, false,
+                    (int) strength);
+            mEnabledAlwaysOnEffects.put(id, prebaked);
+        }
+
+        public void alwaysOnDisable(long id) {
+            mEnabledAlwaysOnEffects.remove(id);
+        }
+
+        private void applyLatency() {
+            try {
+                if (mLatency > 0) {
+                    Thread.sleep(mLatency);
+                }
+            } catch (InterruptedException e) {
+            }
+        }
+
+        private void scheduleListener(long vibrationDuration, long vibrationId) {
+            mHandler.postDelayed(() -> listener.onComplete(vibratorId, vibrationId),
+                    vibrationDuration);
+        }
+    }
+
+    public FakeVibratorControllerProvider(Looper looper) {
+        mHandler = new Handler(looper);
+        mNativeWrapper = new FakeNativeWrapper();
+    }
+
+    public VibratorController newVibratorController(
+            int vibratorId, OnVibrationCompleteListener listener) {
+        return new VibratorController(vibratorId, listener, mNativeWrapper);
+    }
+
+    /** Return {@code true} if this controller was initialized. */
+    public boolean isInitialized() {
+        return mNativeWrapper.isInitialized;
+    }
+
+    /**
+     * Disable fake vibrator hardware, mocking a state where the underlying service is unavailable.
+     */
+    public void disableVibrators() {
+        mIsAvailable = false;
+    }
+
+    /**
+     * Sets the latency this controller should fake for turning the vibrator hardware on or setting
+     * it's vibration amplitude.
+     */
+    public void setLatency(long millis) {
+        mLatency = millis;
+    }
+
+    /** Set the capabilities of the fake vibrator hardware. */
+    public void setCapabilities(int... capabilities) {
+        mCapabilities = Arrays.stream(capabilities).reduce(0, (a, b) -> a | b);
+    }
+
+    /** Set the effects supported by the fake vibrator hardware. */
+    public void setSupportedEffects(int... effects) {
+        if (effects != null) {
+            effects = Arrays.copyOf(effects, effects.length);
+            Arrays.sort(effects);
+        }
+        mSupportedEffects = effects;
+    }
+
+    /** Set the primitives supported by the fake vibrator hardware. */
+    public void setSupportedPrimitives(int... primitives) {
+        if (primitives != null) {
+            primitives = Arrays.copyOf(primitives, primitives.length);
+            Arrays.sort(primitives);
+        }
+        mSupportedPrimitives = primitives;
+    }
+
+    /**
+     * Return the amplitudes set by this controller, including zeroes for each time the vibrator was
+     * turned off.
+     */
+    public List<Integer> getAmplitudes() {
+        return new ArrayList<>(mAmplitudes);
+    }
+
+    /** Return list of {@link VibrationEffect} played by this controller, in order. */
+    public List<VibrationEffect> getEffects() {
+        return new ArrayList<>(mEffects);
+    }
+
+    /**
+     * Return the {@link VibrationEffect.Prebaked} effect enabled with given id, or {@code null} if
+     * missing or disabled.
+     */
+    @Nullable
+    public VibrationEffect.Prebaked getAlwaysOnEffect(int id) {
+        return mEnabledAlwaysOnEffects.get((long) id);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java b/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java
index ac93ff6..28d313b 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java
@@ -34,6 +34,7 @@
 import android.hardware.input.IInputDevicesChangedListener;
 import android.hardware.input.IInputManager;
 import android.hardware.input.InputManager;
+import android.os.CombinedVibrationEffect;
 import android.os.Handler;
 import android.os.Process;
 import android.os.VibrationAttributes;
@@ -66,6 +67,9 @@
     private static final String REASON = "some reason";
     private static final VibrationAttributes VIBRATION_ATTRIBUTES =
             new VibrationAttributes.Builder().setUsage(VibrationAttributes.USAGE_ALARM).build();
+    private static final VibrationEffect EFFECT = VibrationEffect.createOneShot(100, 255);
+    private static final CombinedVibrationEffect SYNCED_EFFECT =
+            CombinedVibrationEffect.createSynced(EFFECT);
 
     @Rule public MockitoRule rule = MockitoJUnit.rule();
 
@@ -227,10 +231,9 @@
 
     @Test
     public void vibrateIfAvailable_withNoInputDevice_returnsFalse() {
-        VibrationEffect effect = VibrationEffect.createOneShot(100, 255);
         assertFalse(mInputDeviceDelegate.isAvailable());
         assertFalse(mInputDeviceDelegate.vibrateIfAvailable(
-                UID, PACKAGE_NAME, effect, REASON, VIBRATION_ATTRIBUTES));
+                UID, PACKAGE_NAME, SYNCED_EFFECT, REASON, VIBRATION_ATTRIBUTES));
     }
 
     @Test
@@ -241,11 +244,10 @@
         when(mIInputManagerMock.getInputDevice(eq(2))).thenReturn(createInputDeviceWithVibrator(2));
         mInputDeviceDelegate.updateInputDeviceVibrators(/* vibrateInputDevices= */ true);
 
-        VibrationEffect effect = VibrationEffect.createOneShot(100, 255);
         assertTrue(mInputDeviceDelegate.vibrateIfAvailable(
-                UID, PACKAGE_NAME, effect, REASON, VIBRATION_ATTRIBUTES));
-        verify(mIInputManagerMock).vibrate(eq(1), same(effect), any());
-        verify(mIInputManagerMock).vibrate(eq(2), same(effect), any());
+                UID, PACKAGE_NAME, SYNCED_EFFECT, REASON, VIBRATION_ATTRIBUTES));
+        verify(mIInputManagerMock).vibrate(eq(1), same(EFFECT), any());
+        verify(mIInputManagerMock).vibrate(eq(2), same(EFFECT), any());
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java
index 1a4ac07..1e6ef91 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java
@@ -26,6 +26,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.ContextWrapper;
+import android.os.CombinedVibrationEffect;
 import android.os.Handler;
 import android.os.IExternalVibratorService;
 import android.os.PowerManagerInternal;
@@ -63,23 +64,23 @@
     @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
     @Rule public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
 
-    // TODO(b/131311651): replace with a FakeVibrator instead.
-    @Mock private Vibrator mVibratorMock;
     @Mock private PowerManagerInternal mPowerManagerInternalMock;
 
     private TestLooper mTestLooper;
     private ContextWrapper mContextSpy;
+    private FakeVibrator mFakeVibrator;
     private VibrationSettings mVibrationSettings;
     private VibrationScaler mVibrationScaler;
 
     @Before
     public void setUp() throws Exception {
         mTestLooper = new TestLooper();
+        mFakeVibrator = new FakeVibrator();
         mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
 
         ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy);
         when(mContextSpy.getContentResolver()).thenReturn(contentResolver);
-        when(mContextSpy.getSystemService(eq(Context.VIBRATOR_SERVICE))).thenReturn(mVibratorMock);
+        when(mContextSpy.getSystemService(eq(Context.VIBRATOR_SERVICE))).thenReturn(mFakeVibrator);
 
         LocalServices.removeServiceForTest(PowerManagerInternal.class);
         LocalServices.addService(PowerManagerInternal.class, mPowerManagerInternalMock);
@@ -96,8 +97,7 @@
 
     @Test
     public void testGetExternalVibrationScale() {
-        when(mVibratorMock.getDefaultHapticFeedbackIntensity())
-                .thenReturn(Vibrator.VIBRATION_INTENSITY_LOW);
+        mFakeVibrator.setDefaultHapticFeedbackIntensity(Vibrator.VIBRATION_INTENSITY_LOW);
         setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_HIGH);
         assertEquals(IExternalVibratorService.SCALE_VERY_HIGH,
@@ -113,13 +113,11 @@
         assertEquals(IExternalVibratorService.SCALE_NONE,
                 mVibrationScaler.getExternalVibrationScale(VibrationAttributes.USAGE_TOUCH));
 
-        when(mVibratorMock.getDefaultHapticFeedbackIntensity())
-                .thenReturn(Vibrator.VIBRATION_INTENSITY_MEDIUM);
+        mFakeVibrator.setDefaultHapticFeedbackIntensity(Vibrator.VIBRATION_INTENSITY_MEDIUM);
         assertEquals(IExternalVibratorService.SCALE_LOW,
                 mVibrationScaler.getExternalVibrationScale(VibrationAttributes.USAGE_TOUCH));
 
-        when(mVibratorMock.getDefaultHapticFeedbackIntensity())
-                .thenReturn(Vibrator.VIBRATION_INTENSITY_HIGH);
+        mFakeVibrator.setDefaultHapticFeedbackIntensity(Vibrator.VIBRATION_INTENSITY_HIGH);
         assertEquals(IExternalVibratorService.SCALE_VERY_LOW,
                 mVibrationScaler.getExternalVibrationScale(VibrationAttributes.USAGE_TOUCH));
 
@@ -131,6 +129,45 @@
     }
 
     @Test
+    public void scale_withCombined_resolvesAndScalesRecursively() {
+        setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_HIGH);
+        VibrationEffect prebaked = VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK);
+        VibrationEffect oneShot = VibrationEffect.createOneShot(10, 10);
+
+        CombinedVibrationEffect.Mono monoScaled = mVibrationScaler.scale(
+                CombinedVibrationEffect.createSynced(prebaked),
+                VibrationAttributes.USAGE_NOTIFICATION);
+        VibrationEffect.Prebaked prebakedScaled = (VibrationEffect.Prebaked) monoScaled.getEffect();
+        assertEquals(prebakedScaled.getEffectStrength(), VibrationEffect.EFFECT_STRENGTH_STRONG);
+
+        CombinedVibrationEffect.Stereo stereoScaled = mVibrationScaler.scale(
+                CombinedVibrationEffect.startSynced()
+                        .addVibrator(1, prebaked)
+                        .addVibrator(2, oneShot)
+                        .combine(),
+                VibrationAttributes.USAGE_NOTIFICATION);
+        prebakedScaled = (VibrationEffect.Prebaked) stereoScaled.getEffects().get(1);
+        assertEquals(prebakedScaled.getEffectStrength(), VibrationEffect.EFFECT_STRENGTH_STRONG);
+        VibrationEffect.OneShot oneshotScaled =
+                (VibrationEffect.OneShot) stereoScaled.getEffects().get(2);
+        assertTrue(oneshotScaled.getAmplitude() > 0);
+
+        CombinedVibrationEffect.Sequential sequentialScaled = mVibrationScaler.scale(
+                CombinedVibrationEffect.startSequential()
+                        .addNext(CombinedVibrationEffect.createSynced(prebaked))
+                        .addNext(CombinedVibrationEffect.createSynced(oneShot))
+                        .combine(),
+                VibrationAttributes.USAGE_NOTIFICATION);
+        monoScaled = (CombinedVibrationEffect.Mono) sequentialScaled.getEffects().get(0);
+        prebakedScaled = (VibrationEffect.Prebaked) monoScaled.getEffect();
+        assertEquals(prebakedScaled.getEffectStrength(), VibrationEffect.EFFECT_STRENGTH_STRONG);
+        monoScaled = (CombinedVibrationEffect.Mono) sequentialScaled.getEffects().get(1);
+        oneshotScaled = (VibrationEffect.OneShot) monoScaled.getEffect();
+        assertTrue(oneshotScaled.getAmplitude() > 0);
+    }
+
+    @Test
     public void scale_withPrebaked_setsEffectStrengthBasedOnSettings() {
         setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_HIGH);
@@ -158,10 +195,31 @@
     }
 
     @Test
+    public void scale_withPrebakedAndFallback_resolvesAndScalesRecursively() {
+        setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_HIGH);
+        VibrationEffect.OneShot fallback2 = (VibrationEffect.OneShot) VibrationEffect.createOneShot(
+                10, VibrationEffect.DEFAULT_AMPLITUDE);
+        VibrationEffect.Prebaked fallback1 = new VibrationEffect.Prebaked(
+                VibrationEffect.EFFECT_TICK, VibrationEffect.EFFECT_STRENGTH_MEDIUM, fallback2);
+        VibrationEffect.Prebaked effect = new VibrationEffect.Prebaked(VibrationEffect.EFFECT_CLICK,
+                VibrationEffect.EFFECT_STRENGTH_MEDIUM, fallback1);
+
+        VibrationEffect.Prebaked scaled = mVibrationScaler.scale(
+                effect, VibrationAttributes.USAGE_NOTIFICATION);
+        VibrationEffect.Prebaked scaledFallback1 =
+                (VibrationEffect.Prebaked) scaled.getFallbackEffect();
+        VibrationEffect.OneShot scaledFallback2 =
+                (VibrationEffect.OneShot) scaledFallback1.getFallbackEffect();
+        assertEquals(scaled.getEffectStrength(), VibrationEffect.EFFECT_STRENGTH_STRONG);
+        assertEquals(scaledFallback1.getEffectStrength(), VibrationEffect.EFFECT_STRENGTH_STRONG);
+        assertTrue(scaledFallback2.getAmplitude() > 0);
+    }
+
+    @Test
     public void scale_withOneShotAndWaveform_resolvesAmplitude() {
         // No scale, default amplitude still resolved
-        when(mVibratorMock.getDefaultRingVibrationIntensity())
-                .thenReturn(Vibrator.VIBRATION_INTENSITY_LOW);
+        mFakeVibrator.setDefaultRingVibrationIntensity(Vibrator.VIBRATION_INTENSITY_LOW);
         setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_LOW);
 
@@ -179,16 +237,13 @@
 
     @Test
     public void scale_withOneShotWaveform_scalesAmplitude() {
-        when(mVibratorMock.getDefaultRingVibrationIntensity())
-                .thenReturn(Vibrator.VIBRATION_INTENSITY_LOW);
+        mFakeVibrator.setDefaultRingVibrationIntensity(Vibrator.VIBRATION_INTENSITY_LOW);
         setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_HIGH);
-        when(mVibratorMock.getDefaultNotificationVibrationIntensity())
-                .thenReturn(Vibrator.VIBRATION_INTENSITY_HIGH);
+        mFakeVibrator.setDefaultNotificationVibrationIntensity(Vibrator.VIBRATION_INTENSITY_HIGH);
         setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_LOW);
-        when(mVibratorMock.getDefaultHapticFeedbackIntensity())
-                .thenReturn(Vibrator.VIBRATION_INTENSITY_MEDIUM);
+        mFakeVibrator.setDefaultHapticFeedbackIntensity(Vibrator.VIBRATION_INTENSITY_MEDIUM);
         setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_MEDIUM);
 
@@ -211,16 +266,13 @@
 
     @Test
     public void scale_withComposed_scalesPrimitives() {
-        when(mVibratorMock.getDefaultRingVibrationIntensity())
-                .thenReturn(Vibrator.VIBRATION_INTENSITY_LOW);
+        mFakeVibrator.setDefaultRingVibrationIntensity(Vibrator.VIBRATION_INTENSITY_LOW);
         setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_HIGH);
-        when(mVibratorMock.getDefaultNotificationVibrationIntensity())
-                .thenReturn(Vibrator.VIBRATION_INTENSITY_HIGH);
+        mFakeVibrator.setDefaultNotificationVibrationIntensity(Vibrator.VIBRATION_INTENSITY_HIGH);
         setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_LOW);
-        when(mVibratorMock.getDefaultHapticFeedbackIntensity())
-                .thenReturn(Vibrator.VIBRATION_INTENSITY_MEDIUM);
+        mFakeVibrator.setDefaultHapticFeedbackIntensity(Vibrator.VIBRATION_INTENSITY_MEDIUM);
         setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_MEDIUM);
 
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
index 1e112da..d867987 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
@@ -76,26 +76,25 @@
     @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
     @Rule public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
 
-    // TODO(b/131311651): replace with a FakeVibrator instead.
-    @Mock private Vibrator mVibratorMock;
     @Mock private VibrationSettings.OnVibratorSettingsChanged mListenerMock;
     @Mock private PowerManagerInternal mPowerManagerInternalMock;
 
     private TestLooper mTestLooper;
     private ContextWrapper mContextSpy;
     private AudioManager mAudioManager;
+    private FakeVibrator mFakeVibrator;
     private VibrationSettings mVibrationSettings;
     private PowerManagerInternal.LowPowerModeListener mRegisteredPowerModeListener;
 
     @Before
     public void setUp() throws Exception {
         mTestLooper = new TestLooper();
+        mFakeVibrator = new FakeVibrator();
         mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
 
         ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy);
         when(mContextSpy.getContentResolver()).thenReturn(contentResolver);
-        when(mContextSpy.getSystemService(eq(Context.VIBRATOR_SERVICE))).thenReturn(mVibratorMock);
-        when(mVibratorMock.hasVibrator()).thenReturn(true);
+        when(mContextSpy.getSystemService(eq(Context.VIBRATOR_SERVICE))).thenReturn(mFakeVibrator);
         doAnswer(invocation -> {
             mRegisteredPowerModeListener = invocation.getArgument(0);
             return null;
@@ -305,12 +304,9 @@
 
     @Test
     public void getDefaultIntensity_returnsIntensityFromVibratorService() {
-        when(mVibratorMock.getDefaultHapticFeedbackIntensity())
-                .thenReturn(Vibrator.VIBRATION_INTENSITY_HIGH);
-        when(mVibratorMock.getDefaultNotificationVibrationIntensity())
-                .thenReturn(Vibrator.VIBRATION_INTENSITY_MEDIUM);
-        when(mVibratorMock.getDefaultRingVibrationIntensity())
-                .thenReturn(Vibrator.VIBRATION_INTENSITY_LOW);
+        mFakeVibrator.setDefaultHapticFeedbackIntensity(Vibrator.VIBRATION_INTENSITY_HIGH);
+        mFakeVibrator.setDefaultNotificationVibrationIntensity(Vibrator.VIBRATION_INTENSITY_MEDIUM);
+        mFakeVibrator.setDefaultRingVibrationIntensity(Vibrator.VIBRATION_INTENSITY_LOW);
 
         setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_OFF);
@@ -336,12 +332,9 @@
 
     @Test
     public void getCurrentIntensity_returnsIntensityFromSettings() {
-        when(mVibratorMock.getDefaultHapticFeedbackIntensity())
-                .thenReturn(Vibrator.VIBRATION_INTENSITY_OFF);
-        when(mVibratorMock.getDefaultNotificationVibrationIntensity())
-                .thenReturn(Vibrator.VIBRATION_INTENSITY_OFF);
-        when(mVibratorMock.getDefaultRingVibrationIntensity())
-                .thenReturn(Vibrator.VIBRATION_INTENSITY_OFF);
+        mFakeVibrator.setDefaultHapticFeedbackIntensity(Vibrator.VIBRATION_INTENSITY_OFF);
+        mFakeVibrator.setDefaultNotificationVibrationIntensity(Vibrator.VIBRATION_INTENSITY_OFF);
+        mFakeVibrator.setDefaultRingVibrationIntensity(Vibrator.VIBRATION_INTENSITY_OFF);
 
         setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_HIGH);
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
new file mode 100644
index 0000000..bee7392
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
@@ -0,0 +1,658 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vibrator;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.hardware.vibrator.IVibrator;
+import android.os.CombinedVibrationEffect;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.os.Process;
+import android.os.SystemClock;
+import android.os.VibrationAttributes;
+import android.os.VibrationEffect;
+import android.os.test.TestLooper;
+import android.platform.test.annotations.Presubmit;
+import android.util.SparseArray;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.internal.app.IBatteryStats;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Tests for {@link VibrationThread}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:VibrationThreadTest
+ */
+@Presubmit
+public class VibrationThreadTest {
+
+    private static final int TEST_TIMEOUT_MILLIS = 1_000;
+    private static final int UID = Process.ROOT_UID;
+    private static final int VIBRATOR_ID = 1;
+    private static final String PACKAGE_NAME = "package";
+    private static final VibrationAttributes ATTRS = new VibrationAttributes.Builder().build();
+
+    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+    @Mock private VibrationThread.VibrationCallbacks mThreadCallbacks;
+    @Mock private VibratorController.OnVibrationCompleteListener mControllerCallbacks;
+    @Mock private IBinder mVibrationToken;
+    @Mock private IBatteryStats mIBatteryStatsMock;
+
+    private final Map<Integer, FakeVibratorControllerProvider> mVibratorProviders = new HashMap<>();
+    private PowerManager.WakeLock mWakeLock;
+    private TestLooper mTestLooper;
+
+    @Before
+    public void setUp() throws Exception {
+        mTestLooper = new TestLooper();
+        mWakeLock = InstrumentationRegistry.getContext().getSystemService(
+                PowerManager.class).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
+
+        mockVibrators(VIBRATOR_ID);
+    }
+
+    @Test
+    public void vibrate_noVibrator_ignoresVibration() {
+        mVibratorProviders.clear();
+        long vibrationId = 1;
+        CombinedVibrationEffect effect = CombinedVibrationEffect.createSynced(
+                VibrationEffect.get(VibrationEffect.EFFECT_CLICK));
+        VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
+        waitForCompletion(thread);
+
+        verify(mControllerCallbacks, never()).onComplete(anyInt(), eq(vibrationId));
+        verify(mThreadCallbacks).onVibrationEnded(eq(vibrationId), eq(Vibration.Status.IGNORED));
+    }
+
+    @Test
+    public void vibrate_missingVibrators_ignoresVibration() {
+        long vibrationId = 1;
+        CombinedVibrationEffect effect = CombinedVibrationEffect.startSequential()
+                .addNext(2, VibrationEffect.get(VibrationEffect.EFFECT_CLICK))
+                .addNext(3, VibrationEffect.get(VibrationEffect.EFFECT_TICK))
+                .combine();
+        VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
+        waitForCompletion(thread);
+
+        verify(mControllerCallbacks, never()).onComplete(anyInt(), eq(vibrationId));
+        verify(mThreadCallbacks).onVibrationEnded(eq(vibrationId), eq(Vibration.Status.IGNORED));
+    }
+
+    @Test
+    public void vibrate_singleVibratorOneShot_runsVibrationAndSetsAmplitude() throws Exception {
+        mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+
+        long vibrationId = 1;
+        VibrationEffect effect = VibrationEffect.createOneShot(10, 100);
+        VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
+        waitForCompletion(thread);
+
+        verify(mIBatteryStatsMock).noteVibratorOn(eq(UID), eq(10L));
+        verify(mIBatteryStatsMock).noteVibratorOff(eq(UID));
+        verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
+        verify(mThreadCallbacks).onVibrationEnded(eq(vibrationId), eq(Vibration.Status.FINISHED));
+        assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
+
+        assertEquals(Arrays.asList(expectedOneShot(10)),
+                mVibratorProviders.get(VIBRATOR_ID).getEffects());
+        assertEquals(Arrays.asList(100), mVibratorProviders.get(VIBRATOR_ID).getAmplitudes());
+    }
+
+    @Test
+    public void vibrate_oneShotWithoutAmplitudeControl_runsVibrationWithDefaultAmplitude()
+            throws Exception {
+        long vibrationId = 1;
+        VibrationEffect effect = VibrationEffect.createOneShot(10, 100);
+        VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
+        waitForCompletion(thread);
+
+        verify(mIBatteryStatsMock).noteVibratorOn(eq(UID), eq(10L));
+        verify(mIBatteryStatsMock).noteVibratorOff(eq(UID));
+        verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
+        verify(mThreadCallbacks).onVibrationEnded(eq(vibrationId), eq(Vibration.Status.FINISHED));
+        assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
+
+        assertEquals(Arrays.asList(expectedOneShot(10)),
+                mVibratorProviders.get(VIBRATOR_ID).getEffects());
+        assertTrue(mVibratorProviders.get(VIBRATOR_ID).getAmplitudes().isEmpty());
+    }
+
+    @Test
+    public void vibrate_singleVibratorWaveform_runsVibrationAndChangesAmplitudes()
+            throws Exception {
+        mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+
+        long vibrationId = 1;
+        VibrationEffect effect = VibrationEffect.createWaveform(
+                new long[]{5, 5, 5}, new int[]{1, 2, 3}, -1);
+        VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
+        waitForCompletion(thread);
+
+        verify(mIBatteryStatsMock).noteVibratorOn(eq(UID), eq(15L));
+        verify(mIBatteryStatsMock).noteVibratorOff(eq(UID));
+        verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
+        verify(mThreadCallbacks).onVibrationEnded(eq(vibrationId), eq(Vibration.Status.FINISHED));
+        assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
+
+        assertEquals(Arrays.asList(expectedOneShot(15)),
+                mVibratorProviders.get(VIBRATOR_ID).getEffects());
+        assertEquals(Arrays.asList(1, 2, 3), mVibratorProviders.get(VIBRATOR_ID).getAmplitudes());
+    }
+
+    @Test
+    public void vibrate_singleVibratorRepeatingWaveform_runsVibrationUntilThreadCancelled()
+            throws Exception {
+        mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+
+        long vibrationId = 1;
+        int[] amplitudes = new int[]{1, 2, 3};
+        VibrationEffect effect = VibrationEffect.createWaveform(new long[]{5, 5, 5}, amplitudes, 0);
+        VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
+
+        Thread.sleep(35);
+        // Vibration still running after 2 cycles.
+        assertTrue(thread.isAlive());
+        assertTrue(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
+
+        thread.cancel();
+        waitForCompletion(thread);
+
+        verify(mIBatteryStatsMock, never()).noteVibratorOn(eq(UID), anyLong());
+        verify(mIBatteryStatsMock, never()).noteVibratorOff(eq(UID));
+        verify(mThreadCallbacks).onVibrationEnded(eq(vibrationId), eq(Vibration.Status.CANCELLED));
+        assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
+
+        List<Integer> playedAmplitudes = mVibratorProviders.get(VIBRATOR_ID).getAmplitudes();
+        assertFalse(mVibratorProviders.get(VIBRATOR_ID).getEffects().isEmpty());
+        assertFalse(playedAmplitudes.isEmpty());
+
+        for (int i = 0; i < playedAmplitudes.size(); i++) {
+            assertEquals(amplitudes[i % amplitudes.length], playedAmplitudes.get(i).intValue());
+        }
+    }
+
+    @Test
+    public void vibrate_singleVibratorPrebaked_runsVibration() throws Exception {
+        mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_THUD);
+
+        long vibrationId = 1;
+        VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_THUD);
+        VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
+        waitForCompletion(thread);
+
+        verify(mIBatteryStatsMock).noteVibratorOn(eq(UID), eq(20L));
+        verify(mIBatteryStatsMock).noteVibratorOff(eq(UID));
+        verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
+        verify(mThreadCallbacks).onVibrationEnded(eq(vibrationId), eq(Vibration.Status.FINISHED));
+        assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
+
+        assertEquals(Arrays.asList(expectedPrebaked(VibrationEffect.EFFECT_THUD)),
+                mVibratorProviders.get(VIBRATOR_ID).getEffects());
+    }
+
+    @Test
+    public void vibrate_singleVibratorPrebakedAndUnsupportedEffectWithFallback_runsFallback()
+            throws Exception {
+        mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+
+        long vibrationId = 1;
+        VibrationEffect fallback = VibrationEffect.createOneShot(10, 100);
+        VibrationEffect.Prebaked effect = new VibrationEffect.Prebaked(VibrationEffect.EFFECT_CLICK,
+                VibrationEffect.EFFECT_STRENGTH_STRONG, fallback);
+        VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
+        waitForCompletion(thread);
+
+        verify(mIBatteryStatsMock).noteVibratorOn(eq(UID), eq(10L));
+        verify(mIBatteryStatsMock).noteVibratorOff(eq(UID));
+        verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
+        verify(mThreadCallbacks).onVibrationEnded(eq(vibrationId), eq(Vibration.Status.FINISHED));
+        assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
+
+        assertEquals(Arrays.asList(expectedOneShot(10)),
+                mVibratorProviders.get(VIBRATOR_ID).getEffects());
+        assertEquals(Arrays.asList(100), mVibratorProviders.get(VIBRATOR_ID).getAmplitudes());
+    }
+
+    @Test
+    public void vibrate_singleVibratorPrebakedAndUnsupportedEffect_ignoresVibration()
+            throws Exception {
+        long vibrationId = 1;
+        VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
+        VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
+        waitForCompletion(thread);
+
+        verify(mIBatteryStatsMock, never()).noteVibratorOn(eq(UID), anyLong());
+        verify(mIBatteryStatsMock, never()).noteVibratorOff(eq(UID));
+        verify(mControllerCallbacks, never()).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
+        verify(mThreadCallbacks).onVibrationEnded(eq(vibrationId),
+                eq(Vibration.Status.IGNORED_UNSUPPORTED));
+        assertTrue(mVibratorProviders.get(VIBRATOR_ID).getEffects().isEmpty());
+    }
+
+    @Test
+    public void vibrate_singleVibratorComposed_runsVibration() throws Exception {
+        mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+
+        long vibrationId = 1;
+        VibrationEffect effect = VibrationEffect.startComposition()
+                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f)
+                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0.5f)
+                .compose();
+        VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
+        waitForCompletion(thread);
+
+        verify(mIBatteryStatsMock).noteVibratorOn(eq(UID), eq(40L));
+        verify(mIBatteryStatsMock).noteVibratorOff(eq(UID));
+        verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
+        verify(mThreadCallbacks).onVibrationEnded(eq(vibrationId), eq(Vibration.Status.FINISHED));
+        assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
+        assertEquals(Arrays.asList(effect), mVibratorProviders.get(VIBRATOR_ID).getEffects());
+    }
+
+    @Test
+    public void vibrate_singleVibratorComposedAndNoCapability_ignoresVibration() throws Exception {
+        long vibrationId = 1;
+        VibrationEffect effect = VibrationEffect.startComposition()
+                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f)
+                .compose();
+        VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
+        waitForCompletion(thread);
+
+        verify(mIBatteryStatsMock, never()).noteVibratorOn(eq(UID), anyLong());
+        verify(mIBatteryStatsMock, never()).noteVibratorOff(eq(UID));
+        verify(mControllerCallbacks, never()).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
+        verify(mThreadCallbacks).onVibrationEnded(eq(vibrationId),
+                eq(Vibration.Status.IGNORED_UNSUPPORTED));
+        assertTrue(mVibratorProviders.get(VIBRATOR_ID).getEffects().isEmpty());
+    }
+
+    @Test
+    public void vibrate_singleVibratorCancelled_vibratorStopped() throws Exception {
+        long vibrationId = 1;
+        VibrationEffect effect = VibrationEffect.createWaveform(new long[]{5}, new int[]{100}, 0);
+        VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
+
+        Thread.sleep(15);
+        // Vibration still running after 2 cycles.
+        assertTrue(thread.isAlive());
+        assertTrue(thread.getVibrators().get(1).isVibrating());
+
+        thread.binderDied();
+        waitForCompletion(thread);
+        assertFalse(thread.getVibrators().get(1).isVibrating());
+
+        verify(mThreadCallbacks).onVibrationEnded(eq(vibrationId), eq(Vibration.Status.CANCELLED));
+    }
+
+    @Test
+    public void vibrate_multipleExistingAndMissingVibrators_vibratesOnlyExistingOnes()
+            throws Exception {
+        mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_TICK);
+
+        long vibrationId = 1;
+        CombinedVibrationEffect effect = CombinedVibrationEffect.startSynced()
+                .addVibrator(VIBRATOR_ID, VibrationEffect.get(VibrationEffect.EFFECT_TICK))
+                .addVibrator(2, VibrationEffect.get(VibrationEffect.EFFECT_TICK))
+                .combine();
+        VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
+        waitForCompletion(thread);
+
+        verify(mIBatteryStatsMock).noteVibratorOn(eq(UID), eq(20L));
+        verify(mIBatteryStatsMock).noteVibratorOff(eq(UID));
+        verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
+        verify(mControllerCallbacks, never()).onComplete(eq(2), eq(vibrationId));
+        verify(mThreadCallbacks).onVibrationEnded(eq(vibrationId), eq(Vibration.Status.FINISHED));
+        assertFalse(thread.getVibrators().get(VIBRATOR_ID).isVibrating());
+
+        assertEquals(Arrays.asList(expectedPrebaked(VibrationEffect.EFFECT_TICK)),
+                mVibratorProviders.get(VIBRATOR_ID).getEffects());
+    }
+
+    @Test
+    public void vibrate_multipleMono_runsSameEffectInAllVibrators() throws Exception {
+        mockVibrators(1, 2, 3);
+        mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
+        mVibratorProviders.get(2).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
+        mVibratorProviders.get(3).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
+
+        long vibrationId = 1;
+        CombinedVibrationEffect effect = CombinedVibrationEffect.createSynced(
+                VibrationEffect.get(VibrationEffect.EFFECT_CLICK));
+        VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
+        waitForCompletion(thread);
+
+        verify(mIBatteryStatsMock).noteVibratorOn(eq(UID), eq(20L));
+        verify(mIBatteryStatsMock).noteVibratorOff(eq(UID));
+        verify(mControllerCallbacks).onComplete(eq(1), eq(vibrationId));
+        verify(mControllerCallbacks).onComplete(eq(2), eq(vibrationId));
+        verify(mControllerCallbacks).onComplete(eq(3), eq(vibrationId));
+        verify(mThreadCallbacks).onVibrationEnded(eq(vibrationId), eq(Vibration.Status.FINISHED));
+        assertFalse(thread.getVibrators().get(1).isVibrating());
+        assertFalse(thread.getVibrators().get(2).isVibrating());
+        assertFalse(thread.getVibrators().get(3).isVibrating());
+
+        VibrationEffect expected = expectedPrebaked(VibrationEffect.EFFECT_CLICK);
+        assertEquals(Arrays.asList(expected), mVibratorProviders.get(1).getEffects());
+        assertEquals(Arrays.asList(expected), mVibratorProviders.get(2).getEffects());
+        assertEquals(Arrays.asList(expected), mVibratorProviders.get(3).getEffects());
+    }
+
+    @Test
+    public void vibrate_multipleStereo_runsVibrationOnRightVibrators() throws Exception {
+        mockVibrators(1, 2, 3, 4);
+        mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
+        mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        mVibratorProviders.get(3).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        mVibratorProviders.get(4).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+
+        long vibrationId = 1;
+        VibrationEffect composed = VibrationEffect.startComposition()
+                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK)
+                .compose();
+        CombinedVibrationEffect effect = CombinedVibrationEffect.startSynced()
+                .addVibrator(1, VibrationEffect.get(VibrationEffect.EFFECT_CLICK))
+                .addVibrator(2, VibrationEffect.createOneShot(10, 100))
+                .addVibrator(3, VibrationEffect.createWaveform(
+                        new long[]{10, 10}, new int[]{1, 2}, -1))
+                .addVibrator(4, composed)
+                .combine();
+        VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
+        waitForCompletion(thread);
+
+        verify(mIBatteryStatsMock).noteVibratorOn(eq(UID), eq(20L));
+        verify(mIBatteryStatsMock).noteVibratorOff(eq(UID));
+        verify(mControllerCallbacks).onComplete(eq(1), eq(vibrationId));
+        verify(mControllerCallbacks).onComplete(eq(2), eq(vibrationId));
+        verify(mControllerCallbacks).onComplete(eq(3), eq(vibrationId));
+        verify(mControllerCallbacks).onComplete(eq(4), eq(vibrationId));
+        verify(mThreadCallbacks).onVibrationEnded(eq(vibrationId), eq(Vibration.Status.FINISHED));
+        assertFalse(thread.getVibrators().get(1).isVibrating());
+        assertFalse(thread.getVibrators().get(2).isVibrating());
+        assertFalse(thread.getVibrators().get(3).isVibrating());
+        assertFalse(thread.getVibrators().get(4).isVibrating());
+
+        assertEquals(Arrays.asList(expectedPrebaked(VibrationEffect.EFFECT_CLICK)),
+                mVibratorProviders.get(1).getEffects());
+        assertEquals(Arrays.asList(expectedOneShot(10)), mVibratorProviders.get(2).getEffects());
+        assertEquals(Arrays.asList(100), mVibratorProviders.get(2).getAmplitudes());
+        assertEquals(Arrays.asList(expectedOneShot(20)), mVibratorProviders.get(3).getEffects());
+        assertEquals(Arrays.asList(1, 2), mVibratorProviders.get(3).getAmplitudes());
+        assertEquals(Arrays.asList(composed), mVibratorProviders.get(4).getEffects());
+    }
+
+    @Test
+    public void vibrate_multipleSequential_runsVibrationInOrderWithDelays()
+            throws Exception {
+        mockVibrators(1, 2, 3);
+        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+        mVibratorProviders.get(3).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
+
+        long vibrationId = 1;
+        VibrationEffect composed = VibrationEffect.startComposition()
+                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK)
+                .compose();
+        CombinedVibrationEffect effect = CombinedVibrationEffect.startSequential()
+                .addNext(3, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), /* delay= */ 50)
+                .addNext(1, VibrationEffect.createOneShot(10, 100), /* delay= */ 50)
+                .addNext(2, composed, /* delay= */ 50)
+                .combine();
+        VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
+
+        waitForCompletion(thread);
+        InOrder controllerVerifier = inOrder(mControllerCallbacks);
+        controllerVerifier.verify(mControllerCallbacks).onComplete(eq(3), eq(vibrationId));
+        controllerVerifier.verify(mControllerCallbacks).onComplete(eq(1), eq(vibrationId));
+        controllerVerifier.verify(mControllerCallbacks).onComplete(eq(2), eq(vibrationId));
+
+        InOrder batterVerifier = inOrder(mIBatteryStatsMock);
+        batterVerifier.verify(mIBatteryStatsMock).noteVibratorOn(eq(UID), eq(20L));
+        batterVerifier.verify(mIBatteryStatsMock).noteVibratorOff(eq(UID));
+        batterVerifier.verify(mIBatteryStatsMock).noteVibratorOn(eq(UID), eq(10L));
+        batterVerifier.verify(mIBatteryStatsMock).noteVibratorOff(eq(UID));
+        batterVerifier.verify(mIBatteryStatsMock).noteVibratorOn(eq(UID), eq(20L));
+        batterVerifier.verify(mIBatteryStatsMock).noteVibratorOff(eq(UID));
+
+        verify(mThreadCallbacks).onVibrationEnded(eq(vibrationId), eq(Vibration.Status.FINISHED));
+        assertFalse(thread.getVibrators().get(1).isVibrating());
+        assertFalse(thread.getVibrators().get(2).isVibrating());
+        assertFalse(thread.getVibrators().get(3).isVibrating());
+
+        assertEquals(Arrays.asList(expectedOneShot(10)), mVibratorProviders.get(1).getEffects());
+        assertEquals(Arrays.asList(100), mVibratorProviders.get(1).getAmplitudes());
+        assertEquals(Arrays.asList(composed), mVibratorProviders.get(2).getEffects());
+        assertEquals(Arrays.asList(expectedPrebaked(VibrationEffect.EFFECT_CLICK)),
+                mVibratorProviders.get(3).getEffects());
+    }
+
+    @Test
+    public void vibrate_multipleWaveforms_playsWaveformsInParallel() throws Exception {
+        mockVibrators(1, 2, 3);
+        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        mVibratorProviders.get(3).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+
+        long vibrationId = 1;
+        CombinedVibrationEffect effect = CombinedVibrationEffect.startSynced()
+                .addVibrator(1, VibrationEffect.createWaveform(
+                        new long[]{5, 10, 10}, new int[]{1, 2, 3}, -1))
+                .addVibrator(2, VibrationEffect.createWaveform(
+                        new long[]{20, 60}, new int[]{4, 5}, -1))
+                .addVibrator(3, VibrationEffect.createWaveform(
+                        new long[]{60}, new int[]{6}, -1))
+                .combine();
+        VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
+
+        Thread.sleep(40);
+        // First waveform has finished.
+        verify(mControllerCallbacks).onComplete(eq(1), eq(vibrationId));
+        assertEquals(Arrays.asList(1, 2, 3), mVibratorProviders.get(1).getAmplitudes());
+        // Second waveform is halfway through.
+        assertEquals(Arrays.asList(4, 5), mVibratorProviders.get(2).getAmplitudes());
+        // Third waveform is almost ending.
+        assertEquals(Arrays.asList(6), mVibratorProviders.get(3).getAmplitudes());
+
+        waitForCompletion(thread);
+
+        verify(mIBatteryStatsMock).noteVibratorOn(eq(UID), eq(80L));
+        verify(mIBatteryStatsMock).noteVibratorOff(eq(UID));
+        verify(mControllerCallbacks).onComplete(eq(2), eq(vibrationId));
+        verify(mControllerCallbacks).onComplete(eq(3), eq(vibrationId));
+        verify(mThreadCallbacks).onVibrationEnded(eq(vibrationId), eq(Vibration.Status.FINISHED));
+        assertFalse(thread.getVibrators().get(1).isVibrating());
+        assertFalse(thread.getVibrators().get(2).isVibrating());
+        assertFalse(thread.getVibrators().get(3).isVibrating());
+
+        assertEquals(Arrays.asList(expectedOneShot(25)), mVibratorProviders.get(1).getEffects());
+        assertEquals(Arrays.asList(expectedOneShot(80)), mVibratorProviders.get(2).getEffects());
+        assertEquals(Arrays.asList(expectedOneShot(60)), mVibratorProviders.get(3).getEffects());
+        assertEquals(Arrays.asList(1, 2, 3), mVibratorProviders.get(1).getAmplitudes());
+        assertEquals(Arrays.asList(4, 5), mVibratorProviders.get(2).getAmplitudes());
+        assertEquals(Arrays.asList(6), mVibratorProviders.get(3).getAmplitudes());
+    }
+
+    @Test
+    public void vibrate_withWaveform_totalVibrationTimeRespected() {
+        int totalDuration = 10_000; // 10s
+        int stepDuration = 25; // 25ms
+
+        // 25% of the first waveform step will be spent on the native on() call.
+        // 25% of each waveform step will be spent on the native setAmplitude() call..
+        mVibratorProviders.get(VIBRATOR_ID).setLatency(stepDuration / 4);
+        mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+
+        int stepCount = totalDuration / stepDuration;
+        long[] timings = new long[stepCount];
+        int[] amplitudes = new int[stepCount];
+        Arrays.fill(timings, stepDuration);
+        Arrays.fill(amplitudes, VibrationEffect.DEFAULT_AMPLITUDE);
+        VibrationEffect effect = VibrationEffect.createWaveform(timings, amplitudes, -1);
+
+        long vibrationId = 1;
+        VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
+        long startTime = SystemClock.elapsedRealtime();
+
+        waitForCompletion(thread, totalDuration + TEST_TIMEOUT_MILLIS);
+        long delay = Math.abs(SystemClock.elapsedRealtime() - startTime - totalDuration);
+
+        // Allow some delay for thread scheduling and callback triggering.
+        int maxDelay = (int) (0.05 * totalDuration); // < 5% of total duration
+        assertTrue("Waveform with perceived delay of " + delay + "ms,"
+                        + " expected less than " + maxDelay + "ms",
+                delay < maxDelay);
+    }
+
+    @Test
+    public void vibrate_multipleCancelled_allVibratorsStopped() throws Exception {
+        mockVibrators(1, 2, 3);
+        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        mVibratorProviders.get(3).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+
+        long vibrationId = 1;
+        CombinedVibrationEffect effect = CombinedVibrationEffect.startSynced()
+                .addVibrator(1, VibrationEffect.createWaveform(
+                        new long[]{5, 10}, new int[]{1, 2}, 0))
+                .addVibrator(2, VibrationEffect.createWaveform(
+                        new long[]{20, 30}, new int[]{3, 4}, 0))
+                .addVibrator(3, VibrationEffect.createWaveform(
+                        new long[]{10, 40}, new int[]{5, 6}, 0))
+                .combine();
+        VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
+
+        Thread.sleep(15);
+        assertTrue(thread.isAlive());
+        assertTrue(thread.getVibrators().get(1).isVibrating());
+        assertTrue(thread.getVibrators().get(2).isVibrating());
+        assertTrue(thread.getVibrators().get(3).isVibrating());
+
+        thread.cancel();
+        waitForCompletion(thread);
+        assertFalse(thread.getVibrators().get(1).isVibrating());
+        assertFalse(thread.getVibrators().get(2).isVibrating());
+        assertFalse(thread.getVibrators().get(3).isVibrating());
+
+        verify(mThreadCallbacks).onVibrationEnded(eq(vibrationId), eq(Vibration.Status.CANCELLED));
+    }
+
+    @Test
+    public void vibrate_binderDied_cancelsVibration() throws Exception {
+        long vibrationId = 1;
+        VibrationEffect effect = VibrationEffect.createWaveform(new long[]{5}, new int[]{100}, 0);
+        VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
+
+        Thread.sleep(15);
+        // Vibration still running after 2 cycles.
+        assertTrue(thread.isAlive());
+        assertTrue(thread.getVibrators().get(1).isVibrating());
+
+        thread.binderDied();
+        waitForCompletion(thread);
+
+        verify(mVibrationToken).linkToDeath(same(thread), eq(0));
+        verify(mVibrationToken).unlinkToDeath(same(thread), eq(0));
+        verify(mThreadCallbacks).onVibrationEnded(eq(vibrationId), eq(Vibration.Status.CANCELLED));
+        assertFalse(mVibratorProviders.get(VIBRATOR_ID).getEffects().isEmpty());
+        assertFalse(thread.getVibrators().get(1).isVibrating());
+    }
+
+    private void mockVibrators(int... vibratorIds) {
+        for (int vibratorId : vibratorIds) {
+            mVibratorProviders.put(vibratorId,
+                    new FakeVibratorControllerProvider(mTestLooper.getLooper()));
+        }
+    }
+
+    private VibrationThread startThreadAndDispatcher(long vibrationId, VibrationEffect effect) {
+        return startThreadAndDispatcher(vibrationId, CombinedVibrationEffect.createSynced(effect));
+    }
+
+    private VibrationThread startThreadAndDispatcher(long vibrationId,
+            CombinedVibrationEffect effect) {
+        VibrationThread thread = new VibrationThread(createVibration(vibrationId, effect),
+                createVibratorControllers(), mWakeLock, mIBatteryStatsMock, mThreadCallbacks);
+        doAnswer(answer -> {
+            thread.vibratorComplete(answer.getArgument(0));
+            return null;
+        }).when(mControllerCallbacks).onComplete(anyInt(), eq(vibrationId));
+        mTestLooper.startAutoDispatch();
+        thread.start();
+        return thread;
+    }
+
+    private void waitForCompletion(VibrationThread thread) {
+        waitForCompletion(thread, TEST_TIMEOUT_MILLIS);
+    }
+
+    private void waitForCompletion(VibrationThread thread, long timeout) {
+        try {
+            thread.join(timeout);
+        } catch (InterruptedException e) {
+        }
+        assertFalse(thread.isAlive());
+        mTestLooper.dispatchAll();
+    }
+
+    private Vibration createVibration(long id, CombinedVibrationEffect effect) {
+        return new Vibration(mVibrationToken, (int) id, effect, ATTRS, UID, PACKAGE_NAME, "reason");
+    }
+
+    private SparseArray<VibratorController> createVibratorControllers() {
+        SparseArray<VibratorController> array = new SparseArray<>();
+        for (Map.Entry<Integer, FakeVibratorControllerProvider> e : mVibratorProviders.entrySet()) {
+            int id = e.getKey();
+            array.put(id, e.getValue().newVibratorController(id, mControllerCallbacks));
+        }
+        return array;
+    }
+
+    private VibrationEffect expectedOneShot(long millis) {
+        return VibrationEffect.createOneShot(millis, VibrationEffect.DEFAULT_AMPLITUDE);
+    }
+
+    private VibrationEffect expectedPrebaked(int effectId) {
+        return new VibrationEffect.Prebaked(effectId, false,
+                VibrationEffect.EFFECT_STRENGTH_MEDIUM);
+    }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 4d2a478..8c744c9 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -95,6 +95,7 @@
 import android.service.notification.ConversationChannelWrapper;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.TestableContentResolver;
+import android.text.format.DateUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.IntArray;
@@ -3293,6 +3294,95 @@
     }
 
     @Test
+    public void testDeleted_noTime() throws Exception {
+        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
+                mAppOpsManager, mStatsEventBuilderFactory);
+
+        final String xml = "<ranking version=\"1\">\n"
+                + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
+                + "<channel id=\"id\" name=\"hi\" importance=\"3\" deleted=\"true\"/>"
+                + "</package>"
+                + "</ranking>";
+        TypedXmlPullParser parser = Xml.newFastPullParser();
+        parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
+                null);
+        parser.nextTag();
+        mHelper.readXml(parser, false, UserHandle.USER_ALL);
+
+        assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, "id", true));
+    }
+
+    @Test
+    public void testDeleted_recentTime() throws Exception {
+        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
+                mAppOpsManager, mStatsEventBuilderFactory);
+
+        mHelper.createNotificationChannel(
+                PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false);
+        mHelper.deleteNotificationChannel(PKG_P, UID_P, "id");
+        NotificationChannel nc1 = mHelper.getNotificationChannel(PKG_P, UID_P, "id", true);
+        assertTrue(DateUtils.isToday(nc1.getDeletedTimeMs()));
+        assertTrue(nc1.isDeleted());
+
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_P, UID_P, false,
+                UserHandle.USER_SYSTEM, "id", NotificationChannel.DEFAULT_CHANNEL_ID);
+
+        TypedXmlPullParser parser = Xml.newFastPullParser();
+        parser.setInput(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())),
+                null);
+        parser.nextTag();
+        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
+                mAppOpsManager, mStatsEventBuilderFactory);
+        mHelper.readXml(parser, true, UserHandle.USER_SYSTEM);
+
+        NotificationChannel nc = mHelper.getNotificationChannel(PKG_P, UID_P, "id", true);
+        assertTrue(DateUtils.isToday(nc.getDeletedTimeMs()));
+        assertTrue(nc.isDeleted());
+    }
+
+    @Test
+    public void testUnDelete_time() throws Exception {
+        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
+                mAppOpsManager, mStatsEventBuilderFactory);
+
+        mHelper.createNotificationChannel(
+                PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false);
+        mHelper.deleteNotificationChannel(PKG_P, UID_P, "id");
+        NotificationChannel nc1 = mHelper.getNotificationChannel(PKG_P, UID_P, "id", true);
+        assertTrue(DateUtils.isToday(nc1.getDeletedTimeMs()));
+        assertTrue(nc1.isDeleted());
+
+        mHelper.createNotificationChannel(
+                PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false);
+        nc1 = mHelper.getNotificationChannel(PKG_P, UID_P, "id", true);
+        assertEquals(-1, nc1.getDeletedTimeMs());
+        assertFalse(nc1.isDeleted());
+    }
+
+    @Test
+    public void testDeleted_longTime() throws Exception {
+        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
+                mAppOpsManager, mStatsEventBuilderFactory);
+
+        long time = System.currentTimeMillis() - (DateUtils.DAY_IN_MILLIS * 30);
+
+        final String xml = "<ranking version=\"1\">\n"
+                + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
+                + "<channel id=\"id\" name=\"hi\" importance=\"3\" deleted=\"true\" del_time=\""
+                + time + "\"/>"
+                + "</package>"
+                + "</ranking>";
+        TypedXmlPullParser parser = Xml.newFastPullParser();
+        parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
+                null);
+        parser.nextTag();
+        mHelper.readXml(parser, false, UserHandle.USER_ALL);
+
+        NotificationChannel nc = mHelper.getNotificationChannel(PKG_O, UID_O, "id", true);
+        assertNull(nc);
+    }
+
+    @Test
     public void testGetConversations_all() {
         String convoId = "convo";
         NotificationChannel messages =
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 610edc0..6f584ee 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -79,6 +79,7 @@
 import android.app.WindowConfiguration;
 import android.app.servertransaction.ActivityConfigurationChangeItem;
 import android.app.servertransaction.ClientTransaction;
+import android.app.servertransaction.DestroyActivityItem;
 import android.app.servertransaction.PauseActivityItem;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -1449,6 +1450,19 @@
     }
 
     @Test
+    public void testRemoveImmediately() throws RemoteException {
+        final ActivityRecord activity = createActivityWithTask();
+        final WindowProcessController wpc = activity.app;
+        activity.getTask().removeImmediately("test");
+
+        verify(mAtm.getLifecycleManager()).scheduleTransaction(any(), eq(activity.appToken),
+                isA(DestroyActivityItem.class));
+        assertNull(activity.app);
+        assertEquals(DESTROYED, activity.getState());
+        assertFalse(wpc.hasActivities());
+    }
+
+    @Test
     public void testRemoveFromHistory() {
         final ActivityRecord activity = createActivityWithTask();
         final Task rootTask = activity.getRootTask();
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 9527625..11be74d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -540,6 +540,25 @@
         assertFalse(secondaryDisplay.shouldWaitForSystemDecorWindowsOnBoot());
     }
 
+    @Test
+    public void testImeIsAttachedToDisplayForLetterboxedApp() {
+        final DisplayContent dc = mDisplayContent;
+        final WindowState ws = createWindow(null, TYPE_APPLICATION, dc, "app window");
+        dc.setImeLayeringTarget(ws);
+
+        // Adjust bounds so that matchesRootDisplayAreaBounds() returns false and
+        // hence isLetterboxedAppWindow() returns true.
+        ws.mActivityRecord.getConfiguration().windowConfiguration.setBounds(new Rect(1, 1, 1, 1));
+        assertFalse("matchesRootDisplayAreaBounds() should return false",
+                ws.matchesRootDisplayAreaBounds());
+        assertTrue("isLetterboxedAppWindow() should return true", ws.isLetterboxedAppWindow());
+        assertTrue("IME shouldn't be attached to app",
+                dc.computeImeParent() != dc.getImeTarget(IME_TARGET_LAYERING).getWindow()
+                        .mActivityRecord.getSurfaceControl());
+        assertEquals("IME should be attached to display",
+                dc.getImeContainer().getParent().getSurfaceControl(), dc.computeImeParent());
+    }
+
     private WindowState[] createNotDrawnWindowsOn(DisplayContent displayContent, int... types) {
         final WindowState[] windows = new WindowState[types.length];
         for (int i = 0; i < types.length; i++) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 0f03f68..06784af 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -123,6 +123,15 @@
         updateDisplayFrames();
     }
 
+    void addWindowWithRawInsetsState(WindowState win) {
+        addWindow(win);
+        // Without mPerformLayout in display content, the window cannot see any insets. Override the
+        // insets state with the global one.
+        final InsetsState insetsState =
+                win.getDisplayContent().getInsetsStateController().getRawInsetsState();
+        win.mAboveInsetsState = insetsState;
+    }
+
     public void setRotation(int rotation, boolean includingWindows) {
         mRotation = rotation;
         updateDisplayFrames();
@@ -269,7 +278,7 @@
     @Test
     public void layoutWindowLw_fitStatusBars() {
         mWindow.mAttrs.setFitInsetsTypes(Type.statusBars());
-        addWindow(mWindow);
+        addWindowWithRawInsetsState(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
@@ -281,7 +290,7 @@
     @Test
     public void layoutWindowLw_fitNavigationBars() {
         mWindow.mAttrs.setFitInsetsTypes(Type.navigationBars());
-        addWindow(mWindow);
+        addWindowWithRawInsetsState(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
@@ -293,7 +302,7 @@
     @Test
     public void layoutWindowLw_fitAllSides() {
         mWindow.mAttrs.setFitInsetsSides(Side.all());
-        addWindow(mWindow);
+        addWindowWithRawInsetsState(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
@@ -305,7 +314,7 @@
     @Test
     public void layoutWindowLw_fitTopOnly() {
         mWindow.mAttrs.setFitInsetsSides(Side.TOP);
-        addWindow(mWindow);
+        addWindowWithRawInsetsState(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
@@ -316,11 +325,12 @@
 
     @Test
     public void layoutWindowLw_fitInsetsIgnoringVisibility() {
-        final InsetsState state = mWindow.getInsetsState();
+        final InsetsState state =
+                mDisplayContent.getInsetsStateController().getRawInsetsState();
         state.getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
         state.getSource(InsetsState.ITYPE_NAVIGATION_BAR).setVisible(false);
         mWindow.mAttrs.setFitInsetsIgnoringVisibility(true);
-        addWindow(mWindow);
+        addWindowWithRawInsetsState(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
@@ -331,11 +341,12 @@
 
     @Test
     public void layoutWindowLw_fitInsetsNotIgnoringVisibility() {
-        final InsetsState state = mWindow.getInsetsState();
+        final InsetsState state =
+                mDisplayContent.getInsetsStateController().getRawInsetsState();
         state.getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
         state.getSource(InsetsState.ITYPE_NAVIGATION_BAR).setVisible(false);
         mWindow.mAttrs.setFitInsetsIgnoringVisibility(false);
-        addWindow(mWindow);
+        addWindowWithRawInsetsState(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
@@ -352,8 +363,7 @@
         state.getSource(InsetsState.ITYPE_IME).setFrame(
                 0, DISPLAY_HEIGHT - IME_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT);
         mWindow.mAttrs.privateFlags |= PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
-        mWindow.mBehindIme = true;
-        addWindow(mWindow);
+        addWindowWithRawInsetsState(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
@@ -368,7 +378,7 @@
 
         mWindow.mAttrs.setFitInsetsTypes(Type.displayCutout());
         mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-        addWindow(mWindow);
+        addWindowWithRawInsetsState(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
@@ -384,7 +394,7 @@
         mWindow.mAttrs.flags =
                 FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
         mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
-        addWindow(mWindow);
+        addWindowWithRawInsetsState(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
@@ -401,7 +411,7 @@
                 FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
         mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
         mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
-        addWindow(mWindow);
+        addWindowWithRawInsetsState(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
@@ -418,7 +428,7 @@
                 FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
         mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
         mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-        addWindow(mWindow);
+        addWindowWithRawInsetsState(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
@@ -435,7 +445,7 @@
                 FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
         mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
         mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-        addWindow(mWindow);
+        addWindowWithRawInsetsState(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
@@ -453,7 +463,7 @@
         mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
         mWindow.mAttrs.setFitInsetsTypes(
                 mWindow.mAttrs.getFitInsetsTypes() & ~Type.statusBars());
-        addWindow(mWindow);
+        addWindowWithRawInsetsState(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
@@ -469,11 +479,12 @@
         mWindow.mAttrs.flags =
                 FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
         mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
-        mWindow.getInsetsState().getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
+        mDisplayContent.getInsetsStateController().getRawInsetsState()
+                .getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
         final InsetsState requestedState = new InsetsState();
         requestedState.getSource(ITYPE_STATUS_BAR).setVisible(false);
         mWindow.updateRequestedVisibility(requestedState);
-        addWindow(mWindow);
+        addWindowWithRawInsetsState(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
@@ -489,12 +500,13 @@
         mWindow.mAttrs.flags =
                 FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
         mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
-        mWindow.getInsetsState().getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
+        mDisplayContent.getInsetsStateController().getRawInsetsState()
+                .getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
         final InsetsState requestedState = new InsetsState();
         requestedState.getSource(ITYPE_STATUS_BAR).setVisible(false);
         mWindow.updateRequestedVisibility(requestedState);
         mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-        addWindow(mWindow);
+        addWindowWithRawInsetsState(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
@@ -511,7 +523,7 @@
         mWindow.mAttrs.flags =
                 FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
         mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
-        addWindow(mWindow);
+        addWindowWithRawInsetsState(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
@@ -528,7 +540,7 @@
         mWindow.mAttrs.flags =
                 FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
         mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
-        addWindow(mWindow);
+        addWindowWithRawInsetsState(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
@@ -547,7 +559,7 @@
         mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
         mWindow.mAttrs.setFitInsetsTypes(
                 mWindow.mAttrs.getFitInsetsTypes() & ~Type.statusBars());
-        addWindow(mWindow);
+        addWindowWithRawInsetsState(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
@@ -564,7 +576,7 @@
         mWindow.mAttrs.type = TYPE_APPLICATION_OVERLAY;
         mWindow.mAttrs.width = DISPLAY_WIDTH;
         mWindow.mAttrs.height = DISPLAY_HEIGHT;
-        addWindow(mWindow);
+        addWindowWithRawInsetsState(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
@@ -584,7 +596,7 @@
         mWindow.mAttrs.setFitInsetsTypes(
                 mWindow.mAttrs.getFitInsetsTypes() & ~Type.statusBars());
         mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-        addWindow(mWindow);
+        addWindowWithRawInsetsState(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
@@ -599,7 +611,7 @@
         mWindow.mAttrs.flags =
                 FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
         mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
-        addWindow(mWindow);
+        addWindowWithRawInsetsState(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
@@ -616,7 +628,7 @@
                 FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
         mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
         mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
-        addWindow(mWindow);
+        addWindowWithRawInsetsState(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
@@ -633,7 +645,7 @@
                 FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
         mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
         mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-        addWindow(mWindow);
+        addWindowWithRawInsetsState(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
@@ -650,7 +662,7 @@
                 FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
         mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
         mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-        addWindow(mWindow);
+        addWindowWithRawInsetsState(mWindow);
 
         mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
         mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
@@ -665,7 +677,7 @@
                 FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
         mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
         mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_NOTHING;
-        addWindow(mWindow);
+        addWindowWithRawInsetsState(mWindow);
 
         final int forwardedInsetBottom = 50;
         mDisplayPolicy.setForwardedInsets(Insets.of(0, 0, 0, forwardedInsetBottom));
@@ -815,9 +827,13 @@
         mDisplayPolicy.beginLayoutLw(mFrames, mDisplayContent.getConfiguration().uiMode);
         doReturn((mDisplayContent.getRotation() + 1) % 4).when(mDisplayContent)
                 .rotationForActivityInDifferentOrientation(eq(mWindow.mActivityRecord));
-        final Rect frame = mWindow.getInsetsState().getSource(ITYPE_STATUS_BAR).getFrame();
+        mWindow.mAboveInsetsState.addSource(mDisplayContent.getInsetsStateController()
+                .getRawInsetsState().peekSource(ITYPE_STATUS_BAR));
+        final Rect frame = mDisplayPolicy.getInsetsPolicy().getInsetsForWindow(mWindow)
+                .getSource(ITYPE_STATUS_BAR).getFrame();
         mDisplayContent.rotateInDifferentOrientationIfNeeded(mWindow.mActivityRecord);
-        final Rect rotatedFrame = mWindow.getInsetsState().getSource(ITYPE_STATUS_BAR).getFrame();
+        final Rect rotatedFrame = mDisplayPolicy.getInsetsPolicy().getInsetsForWindow(mWindow)
+                .getSource(ITYPE_STATUS_BAR).getFrame();
 
         assertEquals(DISPLAY_WIDTH, frame.width());
         assertEquals(DISPLAY_HEIGHT, rotatedFrame.width());
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index 79b2da1..22ee7e4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -22,8 +22,6 @@
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
-import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE;
-import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_TOUCH;
 import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
 import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
@@ -32,13 +30,11 @@
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM;
 import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_RIGHT;
 
@@ -47,7 +43,6 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
@@ -293,46 +288,6 @@
         return win;
     }
 
-    @UseTestDisplay(
-            addWindows = { W_ACTIVITY, W_STATUS_BAR, W_NAVIGATION_BAR, W_NOTIFICATION_SHADE })
-    @Test
-    public void testUpdateHideNavInputEventReceiver() {
-        final InsetsPolicy insetsPolicy = mDisplayContent.getInsetsPolicy();
-        final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
-        displayPolicy.addWindowLw(mStatusBarWindow, mStatusBarWindow.mAttrs);
-        displayPolicy.addWindowLw(mNavBarWindow, mNavBarWindow.mAttrs);
-        displayPolicy.addWindowLw(mNotificationShadeWindow, mNotificationShadeWindow.mAttrs);
-        spyOn(displayPolicy);
-        doReturn(true).when(displayPolicy).hasNavigationBar();
-
-        // App doesn't request to hide navigation bar.
-        insetsPolicy.updateBarControlTarget(mAppWindow);
-        assertNull(displayPolicy.mInputConsumer);
-
-        // App requests to hide navigation bar.
-        final InsetsState requestedState = new InsetsState();
-        requestedState.getSource(ITYPE_NAVIGATION_BAR).setVisible(false);
-        mAppWindow.updateRequestedVisibility(requestedState);
-        insetsPolicy.onInsetsModified(mAppWindow);
-        assertNotNull(displayPolicy.mInputConsumer);
-
-        // App still requests to hide navigation bar, but without BEHAVIOR_SHOW_BARS_BY_TOUCH.
-        mAppWindow.mAttrs.insetsFlags.behavior = BEHAVIOR_SHOW_BARS_BY_SWIPE;
-        insetsPolicy.updateBarControlTarget(mAppWindow);
-        assertNull(displayPolicy.mInputConsumer);
-
-        // App still requests to hide navigation bar, but with BEHAVIOR_SHOW_BARS_BY_TOUCH.
-        mAppWindow.mAttrs.insetsFlags.behavior = BEHAVIOR_SHOW_BARS_BY_TOUCH;
-        insetsPolicy.updateBarControlTarget(mAppWindow);
-        assertNotNull(displayPolicy.mInputConsumer);
-
-        // App still requests to hide navigation bar with BEHAVIOR_SHOW_BARS_BY_TOUCH,
-        // but notification shade forcibly shows navigation bar
-        mNotificationShadeWindow.mAttrs.privateFlags |= PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
-        insetsPolicy.updateBarControlTarget(mAppWindow);
-        assertNull(displayPolicy.mInputConsumer);
-    }
-
     @UseTestDisplay(addWindows = { W_NAVIGATION_BAR, W_INPUT_METHOD })
     @Test
     public void testImeMinimalSourceFrame() {
@@ -346,6 +301,8 @@
 
         displayPolicy.addWindowLw(mNavBarWindow, mNavBarWindow.mAttrs);
         mNavBarWindow.getControllableInsetProvider().setServerVisible(true);
+        final InsetsState state = mDisplayContent.getInsetsStateController().getRawInsetsState();
+        mImeWindow.mAboveInsetsState = state;
 
         mDisplayContent.setInputMethodWindowLocked(mImeWindow);
         mImeWindow.mAttrs.setFitInsetsSides(Side.all() & ~Side.BOTTOM);
@@ -355,7 +312,6 @@
         displayPolicy.beginLayoutLw(mDisplayContent.mDisplayFrames, 0 /* UI mode */);
         displayPolicy.layoutWindowLw(mImeWindow, null, mDisplayContent.mDisplayFrames);
 
-        final InsetsState state = mDisplayContent.getInsetsStateController().getRawInsetsState();
         final InsetsSource imeSource = state.peekSource(ITYPE_IME);
         final InsetsSource navBarSource = state.peekSource(ITYPE_NAVIGATION_BAR);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
index 61911b3..e6f24da 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
@@ -33,6 +33,7 @@
 import static android.window.DisplayAreaOrganizer.FEATURE_WINDOWED_MAGNIFICATION;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.wm.SizeCompatTests.prepareLimitedBounds;
 import static com.android.server.wm.SizeCompatTests.prepareUnresizable;
 import static com.android.server.wm.SizeCompatTests.rotateDisplay;
 
@@ -309,6 +310,43 @@
         assertThat(mSecondRoot.findAreaForToken(imeToken)).isEqualTo(imeContainer);
     }
 
+    @Test
+    public void testResizableFixedOrientationApp_taskLevelLetterboxing() {
+        mFirstRoot.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */);
+        mSecondRoot.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */);
+
+        // Launch portrait on first DAG
+        mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
+        prepareLimitedBounds(mFirstActivity, SCREEN_ORIENTATION_PORTRAIT,
+                false /* isUnresizable */);
+
+        // Display in landscape (as opposite to DAG), first DAG and activity in portrait
+        assertThat(mDisplay.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE);
+        assertThat(mFirstRoot.getConfiguration().orientation).isEqualTo(ORIENTATION_PORTRAIT);
+        assertThat(mFirstActivity.getConfiguration().orientation).isEqualTo(ORIENTATION_PORTRAIT);
+        assertThat(mFirstTask.isTaskLetterboxed()).isFalse();
+        assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
+
+        // Launch portrait on second DAG
+        mDisplay.onLastFocusedTaskDisplayAreaChanged(mSecondTda);
+        prepareLimitedBounds(mSecondActivity, SCREEN_ORIENTATION_LANDSCAPE,
+                false /* isUnresizable */);
+
+        // Display in portrait (as opposite to DAG), first DAG and activity in landscape
+        assertThat(mDisplay.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_PORTRAIT);
+        assertThat(mSecondRoot.getConfiguration().orientation).isEqualTo(ORIENTATION_LANDSCAPE);
+        assertThat(mSecondActivity.getConfiguration().orientation).isEqualTo(ORIENTATION_LANDSCAPE);
+        assertThat(mSecondTask.isTaskLetterboxed()).isFalse();
+        assertThat(mSecondActivity.inSizeCompatMode()).isFalse();
+
+        // First activity is letterboxed in portrait as requested.
+        assertThat(mFirstRoot.getConfiguration().orientation).isEqualTo(ORIENTATION_LANDSCAPE);
+        assertThat(mFirstActivity.getConfiguration().orientation).isEqualTo(ORIENTATION_PORTRAIT);
+        assertThat(mFirstTask.isTaskLetterboxed()).isTrue();
+        assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
+
+    }
+
     private void setupImeWindow() {
         final WindowState imeWindow = createWindow(null /* parent */,
                 TYPE_INPUT_METHOD, mDisplay, "mImeWindow");
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
index e0fd379..bf3ed69 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
@@ -45,6 +45,7 @@
 
 import android.app.StatusBarManager;
 import android.platform.test.annotations.Presubmit;
+import android.view.InsetsSource;
 import android.view.InsetsSourceControl;
 import android.view.InsetsState;
 
@@ -272,7 +273,6 @@
         final WindowState navBar = addNonFocusableWindow(TYPE_NAVIGATION_BAR, "navBar");
         navBar.setHasSurface(true);
         navBar.getControllableInsetProvider().setServerVisible(true);
-
         final InsetsPolicy policy = spy(mDisplayContent.getInsetsPolicy());
         doNothing().when(policy).startAnimation(anyBoolean(), any());
 
@@ -337,11 +337,14 @@
     @UseTestDisplay(addWindows = W_ACTIVITY)
     @Test
     public void testAbortTransientBars_bothCanBeAborted_appGetsBothRealControls() {
-        addNonFocusableWindow(TYPE_STATUS_BAR, "statusBar")
-                .getControllableInsetProvider().getSource().setVisible(false);
-        addNonFocusableWindow(TYPE_NAVIGATION_BAR, "navBar")
-                .getControllableInsetProvider().getSource().setVisible(false);
-
+        final InsetsSource statusBarSource = addNonFocusableWindow(TYPE_STATUS_BAR, "statusBar")
+                .getControllableInsetProvider().getSource();
+        final InsetsSource navBarSource = addNonFocusableWindow(TYPE_NAVIGATION_BAR, "navBar")
+                .getControllableInsetProvider().getSource();
+        statusBarSource.setVisible(false);
+        navBarSource.setVisible(false);
+        mAppWindow.mAboveInsetsState.addSource(navBarSource);
+        mAppWindow.mAboveInsetsState.addSource(statusBarSource);
         final InsetsPolicy policy = spy(mDisplayContent.getInsetsPolicy());
         doNothing().when(policy).startAnimation(anyBoolean(), any());
         policy.updateBarControlTarget(mAppWindow);
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index 2766438..2107ab1e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -59,25 +59,6 @@
 public class InsetsStateControllerTest extends WindowTestsBase {
 
     @Test
-    public void testStripForDispatch_notOwn() {
-        final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
-        final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
-        getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
-        statusBar.setControllableInsetProvider(getController().getSourceProvider(ITYPE_STATUS_BAR));
-        assertNotNull(getController().getInsetsForWindow(app).peekSource(ITYPE_STATUS_BAR));
-    }
-
-    @Test
-    public void testStripForDispatch_own() {
-        final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
-        mDisplayContent.getInsetsStateController().getSourceProvider(ITYPE_STATUS_BAR)
-                .setWindow(statusBar, null, null);
-        statusBar.setControllableInsetProvider(getController().getSourceProvider(ITYPE_STATUS_BAR));
-        final InsetsState state = getController().getInsetsForWindow(statusBar);
-        assertNull(state.peekSource(ITYPE_STATUS_BAR));
-    }
-
-    @Test
     public void testStripForDispatch_navBar() {
         final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
         final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
@@ -142,14 +123,15 @@
         getController().getSourceProvider(ITYPE_IME).setWindow(mImeWindow, null, null);
 
         final WindowState app1 = createWindow(null, TYPE_APPLICATION, "app1");
-        app1.mBehindIme = true;
-
         final WindowState app2 = createWindow(null, TYPE_APPLICATION, "app2");
-        app2.mBehindIme = false;
+
+        app1.mAboveInsetsState.addSource(getController().getRawInsetsState().getSource(ITYPE_IME));
 
         getController().getRawInsetsState().setSourceVisible(ITYPE_IME, true);
-        assertFalse(getController().getInsetsForWindow(app2).getSource(ITYPE_IME).isVisible());
-        assertTrue(getController().getInsetsForWindow(app1).getSource(ITYPE_IME).isVisible());
+        assertFalse(getController().getInsetsForWindow(app2).getSource(ITYPE_IME)
+                .isVisible());
+        assertTrue(getController().getInsetsForWindow(app1).getSource(ITYPE_IME)
+                .isVisible());
     }
 
     @UseTestDisplay(addWindows = W_INPUT_METHOD)
@@ -158,7 +140,8 @@
         getController().getSourceProvider(ITYPE_IME).setWindow(mImeWindow, null, null);
 
         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
-        app.mBehindIme = true;
+        app.mAboveInsetsState.getSource(ITYPE_IME).setVisible(true);
+        app.mAboveInsetsState.getSource(ITYPE_IME).setFrame(mImeWindow.getFrame());
 
         getController().getRawInsetsState().setSourceVisible(ITYPE_IME, true);
         assertTrue(getController().getInsetsForWindow(app).getSource(ITYPE_IME).isVisible());
@@ -170,10 +153,10 @@
         getController().getSourceProvider(ITYPE_IME).setWindow(mImeWindow, null, null);
 
         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
-        app.mBehindIme = false;
 
         getController().getRawInsetsState().setSourceVisible(ITYPE_IME, true);
-        assertFalse(getController().getInsetsForWindow(app).getSource(ITYPE_IME).isVisible());
+        assertFalse(getController().getInsetsForWindow(app).getSource(ITYPE_IME)
+                .isVisible());
     }
 
     @UseTestDisplay(addWindows = W_INPUT_METHOD)
@@ -210,7 +193,8 @@
 
         // app won't get visible IME insets while above IME even when IME is visible.
         assertTrue(getController().getRawInsetsState().getSourceOrDefaultVisibility(ITYPE_IME));
-        assertFalse(getController().getInsetsForWindow(app).getSource(ITYPE_IME).isVisible());
+        assertFalse(getController().getInsetsForWindow(app).getSource(ITYPE_IME)
+                .isVisible());
 
         // Reset invocation counter.
         clearInvocations(app);
@@ -219,6 +203,8 @@
         app.mAttrs.flags &= ~FLAG_NOT_FOCUSABLE;
         mDisplayContent.computeImeTarget(true);
         mDisplayContent.applySurfaceChangesTransaction();
+        app.mAboveInsetsState.getSource(ITYPE_IME).setVisible(true);
+        app.mAboveInsetsState.getSource(ITYPE_IME).setFrame(mImeWindow.getFrame());
 
         // Make sure app got notified.
         verify(app, atLeast(1)).notifyInsetsChanged();
@@ -234,6 +220,8 @@
 
         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
         final WindowState child = createWindow(app, TYPE_APPLICATION, "child");
+        app.mAboveInsetsState.set(getController().getRawInsetsState());
+        child.mAboveInsetsState.set(getController().getRawInsetsState());
         child.mAttrs.flags |= FLAG_ALT_FOCUSABLE_IM;
 
         mDisplayContent.computeImeTarget(true);
@@ -242,7 +230,8 @@
 
         getController().getRawInsetsState().setSourceVisible(ITYPE_IME, true);
         assertTrue(getController().getInsetsForWindow(app).getSource(ITYPE_IME).isVisible());
-        assertFalse(getController().getInsetsForWindow(child).getSource(ITYPE_IME).isVisible());
+        assertFalse(getController().getInsetsForWindow(child).getSource(ITYPE_IME)
+                .isVisible());
     }
 
     @UseTestDisplay(addWindows = W_INPUT_METHOD)
@@ -252,6 +241,7 @@
 
         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
         final WindowState child = createWindow(app, TYPE_APPLICATION, "child");
+        app.mAboveInsetsState.addSource(getController().getRawInsetsState().peekSource(ITYPE_IME));
         child.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
         child.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
 
@@ -261,7 +251,8 @@
 
         getController().getRawInsetsState().setSourceVisible(ITYPE_IME, true);
         assertTrue(getController().getInsetsForWindow(app).getSource(ITYPE_IME).isVisible());
-        assertFalse(getController().getInsetsForWindow(child).getSource(ITYPE_IME).isVisible());
+        assertFalse(getController().getInsetsForWindow(child).getSource(ITYPE_IME)
+                .isVisible());
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 4dce451..409bad4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -19,6 +19,7 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 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_NAVIGATION_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast;
@@ -49,7 +50,6 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 
-import android.window.TaskSnapshot;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.os.Binder;
@@ -59,6 +59,7 @@
 import android.util.SparseBooleanArray;
 import android.view.IRecentsAnimationRunner;
 import android.view.SurfaceControl;
+import android.window.TaskSnapshot;
 
 import androidx.test.filters.SmallTest;
 
@@ -99,6 +100,7 @@
         when(mMockRunner.asBinder()).thenReturn(new Binder());
         mController = spy(new RecentsAnimationController(mWm, mMockRunner, mAnimationCallbacks,
                 DEFAULT_DISPLAY));
+        mController.mShouldAttachNavBarToAppDuringTransition = false;
         mRootHomeTask = mDefaultDisplay.getDefaultTaskDisplayArea().getRootHomeTask();
         assertNotNull(mRootHomeTask);
     }
@@ -499,6 +501,48 @@
         assertTrue(childTask.isAnimatingByRecents());
     }
 
+    @Test
+    public void testRestoreNavBarWhenEnteringRecents_expectAnimation() {
+        setupForShouldAttachNavBarDuringTransition();
+        final ActivityRecord activity = createActivityRecord(mDefaultDisplay);
+        final ActivityRecord homeActivity = createHomeActivity();
+        initializeRecentsAnimationController(mController, homeActivity);
+
+        final WindowToken navToken = mDefaultDisplay.getDisplayPolicy().getNavigationBar().mToken;
+        final SurfaceControl.Transaction transaction = navToken.getPendingTransaction();
+
+        verify(transaction).reparent(navToken.getSurfaceControl(), activity.getSurfaceControl());
+
+        final WindowContainer parent = navToken.getParent();
+        final NavBarFadeAnimationController navBarFadeAnimationController =
+                mDefaultDisplay.getDisplayPolicy().getNavBarFadeAnimationController();
+
+        mController.cleanupAnimation(REORDER_MOVE_TO_TOP);
+        verify(transaction).reparent(navToken.getSurfaceControl(), parent.getSurfaceControl());
+        verify(navBarFadeAnimationController).fadeWindowToken(true);
+    }
+
+    @Test
+    public void testRestoreNavBarWhenBackToApp_expectNoAnimation() {
+        setupForShouldAttachNavBarDuringTransition();
+        final ActivityRecord activity = createActivityRecord(mDefaultDisplay);
+        final ActivityRecord homeActivity = createHomeActivity();
+        initializeRecentsAnimationController(mController, homeActivity);
+
+        final WindowToken navToken = mDefaultDisplay.getDisplayPolicy().getNavigationBar().mToken;
+        final SurfaceControl.Transaction transaction = navToken.getPendingTransaction();
+
+        verify(transaction).reparent(navToken.getSurfaceControl(), activity.getSurfaceControl());
+
+        final WindowContainer parent = navToken.getParent();
+        final NavBarFadeAnimationController navBarFadeAnimationController =
+                mDefaultDisplay.getDisplayPolicy().getNavBarFadeAnimationController();
+
+        mController.cleanupAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION);
+        verify(transaction).reparent(navToken.getSurfaceControl(), parent.getSurfaceControl());
+        verify(navBarFadeAnimationController, never()).fadeWindowToken(anyBoolean());
+    }
+
     private ActivityRecord createHomeActivity() {
         final ActivityRecord homeActivity = new ActivityBuilder(mWm.mAtmService)
                 .setParentTask(mRootHomeTask)
@@ -525,6 +569,19 @@
         assertFalse(activity.mDisplayContent.hasTopFixedRotationLaunchingApp());
     }
 
+    private void setupForShouldAttachNavBarDuringTransition() {
+        mController.mShouldAttachNavBarToAppDuringTransition = true;
+        final WindowState navBar = createWindow(null, TYPE_NAVIGATION_BAR, "NavigationBar");
+        mDefaultDisplay.getDisplayPolicy().addWindowLw(navBar, navBar.mAttrs);
+        mWm.setRecentsAnimationController(mController);
+        final NavBarFadeAnimationController mockNavBarFadeAnimationController =
+                mock(NavBarFadeAnimationController.class);
+        final DisplayPolicy displayPolicy = spy(mDefaultDisplay.getDisplayPolicy());
+        doReturn(displayPolicy).when(mDefaultDisplay).getDisplayPolicy();
+        doReturn(mockNavBarFadeAnimationController).when(displayPolicy)
+                .getNavBarFadeAnimationController();
+    }
+
     private static void initializeRecentsAnimationController(RecentsAnimationController controller,
             ActivityRecord activity) {
         controller.initialize(activity.getActivityType(), new SparseBooleanArray(), activity);
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 e190248..eb44476 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -16,12 +16,15 @@
 
 package com.android.server.wm;
 
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
+import static android.view.SurfaceProto.ROTATION_180;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -39,7 +42,6 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.same;
 import static org.mockito.Mockito.clearInvocations;
@@ -243,7 +245,7 @@
         // The bounds should be [800, 0 - 1800, 2500].
         assertEquals(origBounds.width(), currentBounds.width());
         assertEquals(origBounds.height(), currentBounds.height());
-        assertEquals(Configuration.ORIENTATION_LANDSCAPE, display.getConfiguration().orientation);
+        assertEquals(ORIENTATION_LANDSCAPE, display.getConfiguration().orientation);
         assertEquals(Configuration.ORIENTATION_PORTRAIT, mActivity.getConfiguration().orientation);
 
         // The previous resize operation doesn't consider the rotation change after size changed.
@@ -504,7 +506,7 @@
 
         compatTokens.clear();
         // Make the activity resizable again by restarting it
-        activity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
+        activity.info.resizeMode = RESIZE_MODE_RESIZEABLE;
         activity.mVisibleRequested = true;
         activity.restartProcessIfVisible();
         // The full lifecycle isn't hooked up so manually set state to resumed
@@ -521,7 +523,7 @@
         setUpDisplaySizeWithApp(1000, 2500);
 
         // Make the task root resizable.
-        mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
+        mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE;
 
         // Create a size compat activity on the same task.
         final ActivityRecord activity = new ActivityBuilder(mAtm)
@@ -549,7 +551,7 @@
         setUpDisplaySizeWithApp(1000, 2500);
 
         // Make the task root resizable.
-        mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
+        mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE;
 
         // Create a size compat activity on the same task.
         final ActivityRecord activity = new ActivityBuilder(mAtm)
@@ -729,7 +731,7 @@
         // Update with new activity requested orientation and recompute bounds with no previous
         // size compat cache.
         verify(mTask).onDescendantOrientationChanged(same(newActivity));
-        verify(mTask).computeFullscreenBounds(any(), any(), any(), anyInt());
+        verify(mTask).computeFullscreenBounds(any(), any());
 
         final Rect displayBounds = new Rect(display.getBounds());
         final Rect taskBounds = new Rect(mTask.getBounds());
@@ -770,7 +772,7 @@
         // Update with new activity requested orientation and recompute bounds with no previous
         // size compat cache.
         verify(mTask).onDescendantOrientationChanged(same(newActivity));
-        verify(mTask).computeFullscreenBounds(any(), any(), any(), anyInt());
+        verify(mTask).computeFullscreenBounds(any(), any());
 
         final Rect displayBounds = new Rect(display.getBounds());
         final Rect taskBounds = new Rect(mTask.getBounds());
@@ -821,6 +823,88 @@
         assertEquals(activityBounds, mActivity.getBounds());
     }
 
+    @Test
+    public void testDisplayIgnoreOrientationRequest_rotated180_notInSizeCompat() {
+        // Set up a display in landscape and ignoring orientation request.
+        setUpDisplaySizeWithApp(2800, 1400);
+        final DisplayContent display = mActivity.mDisplayContent;
+        display.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+        // Portrait fixed app.
+        prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
+
+        // In Task letterbox
+        assertTrue(mTask.isTaskLetterboxed());
+        assertFalse(mActivity.inSizeCompatMode());
+
+        // Rotate display to portrait.
+        rotateDisplay(display, ROTATION_90);
+
+        // App should be in size compat.
+        assertFalse(mTask.isTaskLetterboxed());
+        assertScaled();
+
+        // Rotate display to landscape.
+        rotateDisplay(display, ROTATION_180);
+
+        // In Task letterbox
+        assertTrue(mTask.isTaskLetterboxed());
+        assertFalse(mActivity.inSizeCompatMode());
+    }
+
+    @Test
+    public void testDisplayIgnoreOrientationRequestWithInsets_rotated180_notInSizeCompat() {
+        // Set up a display in portrait with display cutout and ignoring orientation request.
+        final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1400, 2800)
+                .setNotch(75)
+                .build();
+        setUpApp(display);
+        display.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+        // Landscape fixed app.
+        prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_LANDSCAPE);
+
+        // In Task letterbox
+        assertTrue(mTask.isTaskLetterboxed());
+        assertFalse(mActivity.inSizeCompatMode());
+
+        // Rotate display to portrait.
+        rotateDisplay(display, ROTATION_90);
+
+        // App should be in size compat.
+        assertFalse(mTask.isTaskLetterboxed());
+        assertScaled();
+
+        // Rotate display to landscape.
+        rotateDisplay(display, ROTATION_180);
+
+        // In Task letterbox
+        assertTrue(mTask.isTaskLetterboxed());
+        assertFalse(mActivity.inSizeCompatMode());
+    }
+
+    @Test
+    public void testTaskDisplayAreaNotFillDisplay() {
+        setUpDisplaySizeWithApp(1400, 2800);
+        final DisplayContent display = mActivity.mDisplayContent;
+        final TaskDisplayArea taskDisplayArea = mActivity.getDisplayArea();
+        taskDisplayArea.setBounds(0, 0, 1000, 2400);
+
+        // Portrait fixed app.
+        prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_LANDSCAPE);
+
+        final Rect displayBounds = new Rect(display.getBounds());
+        assertEquals(ORIENTATION_LANDSCAPE, display.getConfiguration().orientation);
+        assertEquals(2800, displayBounds.width());
+        assertEquals(1400, displayBounds.height());
+        taskDisplayArea.setBounds(0, 0, 2400, 1000);
+
+        final Rect activityBounds = new Rect(mActivity.getBounds());
+        assertFalse(mActivity.inSizeCompatMode());
+        assertEquals(2400, activityBounds.width());
+        assertEquals(1000, activityBounds.height());
+    }
+
     private static WindowState addWindowToActivity(ActivityRecord activity) {
         final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
         params.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
@@ -863,13 +947,25 @@
         prepareUnresizable(activity, -1 /* maxAspect */, screenOrientation);
     }
 
-    /**
-     * Setups {@link #mActivity} as a size-compat-mode-able activity with fixed aspect and/or
-     * orientation.
-     */
     static void prepareUnresizable(ActivityRecord activity, float maxAspect,
             int screenOrientation) {
-        activity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+        prepareLimitedBounds(activity, maxAspect, screenOrientation, true /* isUnresizable */);
+    }
+
+    static void prepareLimitedBounds(ActivityRecord activity, int screenOrientation,
+            boolean isUnresizable) {
+        prepareLimitedBounds(activity, -1 /* maxAspect */, screenOrientation, isUnresizable);
+    }
+
+    /**
+     * Setups {@link #mActivity} with restriction on its bounds, such as maxAspect, fixed
+     * orientation, and/or whether it is resizable.
+     */
+    static void prepareLimitedBounds(ActivityRecord activity, float maxAspect,
+            int screenOrientation, boolean isUnresizable) {
+        activity.info.resizeMode = isUnresizable
+                ? RESIZE_MODE_UNRESIZEABLE
+                : RESIZE_MODE_RESIZEABLE;
         activity.mVisibleRequested = true;
         if (maxAspect >= 0) {
             activity.info.maxAspectRatio = maxAspect;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
index 1607f01..a1f89ec 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
@@ -275,7 +275,7 @@
         imeSource.setFrame(imeFrame);
         imeSource.setVisible(true);
         w.updateRequestedVisibility(state);
-        w.mBehindIme = true;
+        w.mAboveInsetsState.addSource(imeSource);
 
         // With no insets or system decor all the frames incoming from PhoneWindowManager
         // are identical.
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index fe7bdd8..d8be2c1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -80,6 +80,8 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.server.wm.TaskOrganizerController.PendingTaskEvent;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -150,10 +152,14 @@
         final ITaskOrganizer organizer = registerMockOrganizer();
         final Task stack = createStack();
         final Task task = createTask(stack);
+        // Ensure events dispatch to organizer.
+        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
 
         verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
 
         stack.removeImmediately();
+        // Ensure events dispatch to organizer.
+        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         verify(organizer).onTaskVanished(any());
     }
 
@@ -162,15 +168,21 @@
         final ITaskOrganizer organizer = registerMockOrganizer();
         final Task stack = createStack();
         final Task task = createTask(stack, false);
+        // Ensure events dispatch to organizer.
+        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
 
         verify(organizer, never())
                 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
         stack.setHasBeenVisible(true);
+        // Ensure events dispatch to organizer.
+        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         assertTrue(stack.getHasBeenVisible());
 
         verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
 
         stack.removeImmediately();
+        // Ensure events dispatch to organizer.
+        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         verify(organizer).onTaskVanished(any());
     }
 
@@ -195,12 +207,16 @@
         final ITaskOrganizer organizer = registerMockOrganizer();
         final Task stack = createStack();
         final Task task = createTask(stack, false /* fakeDraw */);
+        // Ensure events dispatch to organizer.
+        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
 
         verify(organizer, never())
                 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
         assertTrue(stack.isOrganized());
 
         mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer);
+        // Ensure events dispatch to organizer.
+        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         assertTaskVanished(organizer, false /* expectVanished */, stack);
         assertFalse(stack.isOrganized());
     }
@@ -210,11 +226,16 @@
         final ITaskOrganizer organizer = registerMockOrganizer();
         final Task stack = createStack();
         final Task task = createTask(stack);
+        // Ensure events dispatch to organizer.
+        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
 
         verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
         assertTrue(stack.isOrganized());
 
         stack.setTaskOrganizer(null);
+        // Ensure events dispatch to organizer.
+        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
+
         verify(organizer).onTaskVanished(any());
         assertFalse(stack.isOrganized());
     }
@@ -224,11 +245,16 @@
         final ITaskOrganizer organizer = registerMockOrganizer();
         final Task stack = createStack();
         final Task task = createTask(stack);
+        // Ensure events dispatch to organizer.
+        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
 
         verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
         assertTrue(stack.isOrganized());
 
         mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer);
+        // Ensure events dispatch to organizer.
+        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
+
         assertTaskVanished(organizer, true /* expectVanished */, stack);
         assertFalse(stack.isOrganized());
     }
@@ -243,6 +269,8 @@
         final Task task3 = createTask(stack3);
         final ArrayList<TaskAppearedInfo> existingTasks = new ArrayList<>();
         final ITaskOrganizer organizer = registerMockOrganizer(existingTasks);
+        // Ensure events dispatch to organizer.
+        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
 
         // verify that tasks are returned and taskAppeared is not called
         assertContainsTasks(existingTasks, stack, stack2, stack3);
@@ -254,6 +282,8 @@
         // Now we replace the registration and verify the new organizer receives existing tasks
         final ArrayList<TaskAppearedInfo> existingTasks2 = new ArrayList<>();
         final ITaskOrganizer organizer2 = registerMockOrganizer(existingTasks2);
+        // Ensure events dispatch to organizer.
+        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         assertContainsTasks(existingTasks2, stack, stack2, stack3);
         verify(organizer2, times(0)).onTaskAppeared(any(RunningTaskInfo.class),
                 any(SurfaceControl.class));
@@ -265,6 +295,8 @@
         // Now we unregister the second one, the first one should automatically be reregistered
         // so we verify that it's now seeing changes.
         mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer2);
+        // Ensure events dispatch to organizer.
+        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         verify(organizer, times(3))
                 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
         assertTaskVanished(organizer2, true /* expectVanished */, stack, stack2, stack3);
@@ -599,6 +631,8 @@
         Task task = mWm.mAtmService.mTaskOrganizerController.createRootTask(
                 mDisplayContent, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, null);
         RunningTaskInfo info1 = task.getTaskInfo();
+        // Ensure events dispatch to organizer.
+        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         lastReportedTiles.clear();
         called[0] = false;
 
@@ -673,6 +707,8 @@
         Task task2 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
                 mDisplayContent, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, null);
         RunningTaskInfo info2 = task2.getTaskInfo();
+        // Ensure events dispatch to organizer.
+        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
 
         final int initialRootTaskCount = mWm.mAtmService.mTaskOrganizerController.getRootTasks(
                 mDisplayContent.mDisplayId, null /* activityTypes */).size();
@@ -856,6 +892,8 @@
                 .setAspectRatio(new Rational(3, 4)).build();
         mWm.mAtmService.mActivityClientController.setPictureInPictureParams(record.token, p2);
         waitUntilHandlersIdle();
+        // Ensure events dispatch to organizer.
+        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         assertNotNull(o.mChangedInfo);
         assertNotNull(o.mChangedInfo.pictureInPictureParams);
         final Rational ratio = o.mChangedInfo.pictureInPictureParams.getAspectRatioRational();
@@ -895,16 +933,24 @@
         stack.setTaskOrganizer(organizer);
         // setHasBeenVisible was already called once by the set-up code.
         stack.setHasBeenVisible(true);
+        // Ensure events dispatch to organizer.
+        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         verify(organizer, times(1))
                 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
 
         stack.setTaskOrganizer(null);
+        // Ensure events dispatch to organizer.
+        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         verify(organizer, times(1)).onTaskVanished(any());
         stack.setTaskOrganizer(organizer);
+        // Ensure events dispatch to organizer.
+        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         verify(organizer, times(2))
                 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
 
         stack.removeImmediately();
+        // Ensure events dispatch to organizer.
+        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         verify(organizer, times(2)).onTaskVanished(any());
     }
 
@@ -923,6 +969,8 @@
 
         // Verify a back pressed does not call the organizer
         mWm.mAtmService.mActivityClientController.onBackPressedOnTaskRoot(activity.token);
+        // Ensure events dispatch to organizer.
+        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         verify(organizer, never()).onBackPressedOnTaskRoot(any());
 
         // Enable intercepting back
@@ -931,6 +979,8 @@
 
         // Verify now that the back press does call the organizer
         mWm.mAtmService.mActivityClientController.onBackPressedOnTaskRoot(activity.token);
+        // Ensure events dispatch to organizer.
+        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         verify(organizer, times(1)).onBackPressedOnTaskRoot(any());
 
         // Disable intercepting back
@@ -939,6 +989,8 @@
 
         // Verify now that the back press no longer calls the organizer
         mWm.mAtmService.mActivityClientController.onBackPressedOnTaskRoot(activity.token);
+        // Ensure events dispatch to organizer.
+        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         verify(organizer, times(1)).onBackPressedOnTaskRoot(any());
     }
 
@@ -1019,6 +1071,151 @@
         assertTrue(task2.isOrganized());
     }
 
+    @Test
+    public void testAppearDeferThenInfoChange() {
+        final ITaskOrganizer organizer = registerMockOrganizer();
+        final Task stack = createStack();
+
+        // Assume layout defer
+        mWm.mWindowPlacerLocked.deferLayout();
+
+        final Task task = createTask(stack);
+        final ActivityRecord record = createActivityRecord(stack.mDisplayContent, task);
+
+        stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+        record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription"));
+        waitUntilHandlersIdle();
+
+        ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
+        assertEquals(1, pendingEvents.size());
+        assertEquals(PendingTaskEvent.EVENT_APPEARED, pendingEvents.get(0).mEventType);
+        assertEquals("TestDescription",
+                pendingEvents.get(0).mTask.getTaskInfo().taskDescription.getLabel());
+    }
+
+    @Test
+    public void testAppearDeferThenVanish() {
+        final ITaskOrganizer organizer = registerMockOrganizer();
+        final Task stack = createStack();
+
+        // Assume layout defer
+        mWm.mWindowPlacerLocked.deferLayout();
+
+        final Task task = createTask(stack);
+
+        stack.removeImmediately();
+        waitUntilHandlersIdle();
+
+        ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
+        assertEquals(0, pendingEvents.size());
+    }
+
+    @Test
+    public void testInfoChangeDeferMultiple() {
+        final ITaskOrganizer organizer = registerMockOrganizer();
+        final Task stack = createStack();
+        final Task task = createTask(stack);
+        final ActivityRecord record = createActivityRecord(stack.mDisplayContent, task);
+
+        // Assume layout defer
+        mWm.mWindowPlacerLocked.deferLayout();
+
+        stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+        record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription"));
+        waitUntilHandlersIdle();
+
+        ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
+        assertEquals(1, pendingEvents.size());
+        assertEquals(PendingTaskEvent.EVENT_INFO_CHANGED, pendingEvents.get(0).mEventType);
+        assertEquals("TestDescription",
+                pendingEvents.get(0).mTask.getTaskInfo().taskDescription.getLabel());
+
+        record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription2"));
+        waitUntilHandlersIdle();
+
+        pendingEvents = getTaskPendingEvent(stack);
+        assertEquals(1, pendingEvents.size());
+        assertEquals(PendingTaskEvent.EVENT_INFO_CHANGED, pendingEvents.get(0).mEventType);
+        assertEquals("TestDescription2",
+                pendingEvents.get(0).mTask.getTaskInfo().taskDescription.getLabel());
+    }
+
+    @Test
+    public void testInfoChangDeferThenVanish() {
+        final ITaskOrganizer organizer = registerMockOrganizer();
+        final Task stack = createStack();
+        final Task task = createTask(stack);
+        final ActivityRecord record = createActivityRecord(stack.mDisplayContent, task);
+
+        // Assume layout defer
+        mWm.mWindowPlacerLocked.deferLayout();
+
+        stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+        record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription"));
+
+        stack.removeImmediately();
+        waitUntilHandlersIdle();
+
+        ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
+        assertEquals(1, pendingEvents.size());
+        assertEquals(PendingTaskEvent.EVENT_VANISHED, pendingEvents.get(0).mEventType);
+        assertEquals("TestDescription",
+                pendingEvents.get(0).mTask.getTaskInfo().taskDescription.getLabel());
+    }
+
+    @Test
+    public void testVanishDeferThenInfoChange() {
+        final ITaskOrganizer organizer = registerMockOrganizer();
+        final Task stack = createStack();
+        final Task task = createTask(stack);
+        final ActivityRecord record = createActivityRecord(stack.mDisplayContent, task);
+
+        // Assume layout defer
+        mWm.mWindowPlacerLocked.deferLayout();
+
+        stack.removeImmediately();
+        stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+        waitUntilHandlersIdle();
+
+        ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
+        assertEquals(1, pendingEvents.size());
+        assertEquals(PendingTaskEvent.EVENT_VANISHED, pendingEvents.get(0).mEventType);
+    }
+
+    @Test
+    public void testVanishDeferThenBackOnRoot() {
+        final ITaskOrganizer organizer = registerMockOrganizer();
+        final Task stack = createStack();
+        final Task task = createTask(stack);
+        final ActivityRecord record = createActivityRecord(stack.mDisplayContent, task);
+
+        // Assume layout defer
+        mWm.mWindowPlacerLocked.deferLayout();
+
+        stack.removeImmediately();
+        mWm.mAtmService.mActivityClientController.onBackPressedOnTaskRoot(record.token);
+        waitUntilHandlersIdle();
+
+        ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
+        assertEquals(1, pendingEvents.size());
+        assertEquals(PendingTaskEvent.EVENT_VANISHED, pendingEvents.get(0).mEventType);
+    }
+
+    private ArrayList<PendingTaskEvent> getTaskPendingEvent(Task task) {
+        ArrayList<PendingTaskEvent> total =
+                mWm.mAtmService.mTaskOrganizerController.getPendingEventList();
+        ArrayList<PendingTaskEvent> result = new ArrayList();
+
+        for (int i = 0; i < total.size(); i++) {
+            PendingTaskEvent entry = total.get(i);
+            if (entry.mTask.mTaskId == task.mTaskId) {
+                result.add(entry);
+            }
+        }
+
+        return result;
+    }
+
     /**
      * Verifies that task vanished is called for a specific task.
      */
diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
index 811a146..c82ba99 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
@@ -35,11 +35,19 @@
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.server.wm.WindowStateAnimator.PRESERVED_SURFACE_LAYER;
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.os.Binder;
 import android.platform.test.annotations.Presubmit;
+import android.util.SparseBooleanArray;
+import android.view.IRecentsAnimationRunner;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 
@@ -451,4 +459,38 @@
         assertWindowHigher(mDockedDividerWindow, splitScreenSecondaryWindow);
         assertWindowHigher(pinnedStackWindow, mDockedDividerWindow);
     }
+
+    @Test
+    public void testAttachNavBarWhenEnteringRecents_expectNavBarHigherThanIme() {
+        // create RecentsAnimationController
+        IRecentsAnimationRunner mockRunner = mock(IRecentsAnimationRunner.class);
+        when(mockRunner.asBinder()).thenReturn(new Binder());
+        final int displayId = mDisplayContent.getDisplayId();
+        RecentsAnimationController controller = new RecentsAnimationController(
+                mWm, mockRunner, null, displayId);
+        spyOn(controller);
+        controller.mShouldAttachNavBarToAppDuringTransition = true;
+        doReturn(mNavBarWindow.mToken).when(controller).getNavigationBarWindowToken();
+        mWm.setRecentsAnimationController(controller);
+
+        // set ime visible
+        spyOn(mDisplayContent.mInputMethodWindow);
+        doReturn(true).when(mDisplayContent.mInputMethodWindow).isVisible();
+
+        // create home activity
+        Task rootHomeTask = mDisplayContent.getDefaultTaskDisplayArea().getRootHomeTask();
+        final ActivityRecord homeActivity = new ActivityBuilder(mWm.mAtmService)
+                .setParentTask(rootHomeTask)
+                .setCreateTask(true)
+                .build();
+        homeActivity.setVisibility(true);
+
+        // start recent animation
+        controller.initialize(homeActivity.getActivityType(), new SparseBooleanArray(),
+                homeActivity);
+
+        mDisplayContent.assignChildLayers(mTransaction);
+        assertZOrderGreaterThan(mTransaction, mNavBarWindow.mToken.getSurfaceControl(),
+                mDisplayContent.getImeContainer().getSurfaceControl());
+    }
 }
diff --git a/services/translation/java/com/android/server/translation/TranslationManagerService.java b/services/translation/java/com/android/server/translation/TranslationManagerService.java
index e2aabe6..84c6e7b 100644
--- a/services/translation/java/com/android/server/translation/TranslationManagerService.java
+++ b/services/translation/java/com/android/server/translation/TranslationManagerService.java
@@ -22,13 +22,17 @@
 import android.content.Context;
 import android.os.RemoteException;
 import android.util.Slog;
+import android.view.autofill.AutofillId;
 import android.view.translation.ITranslationManager;
 import android.view.translation.TranslationSpec;
+import android.view.translation.UiTranslationManager.UiTranslationState;
 
 import com.android.internal.os.IResultReceiver;
 import com.android.server.infra.AbstractMasterSystemService;
 import com.android.server.infra.FrameworkResourcesServiceNameResolver;
 
+import java.util.List;
+
 /**
  * Entry point service for translation management.
  *
@@ -82,6 +86,19 @@
                 }
             }
         }
+
+        @Override
+        public void updateUiTranslationState(@UiTranslationState int state,
+                TranslationSpec sourceSpec, TranslationSpec destSpec, List<AutofillId> viewIds,
+                int taskId, int userId) {
+            synchronized (mLock) {
+                final TranslationManagerServiceImpl service = getServiceForUserLocked(userId);
+                if (service != null) {
+                    service.updateUiTranslationState(state, sourceSpec, destSpec, viewIds,
+                            taskId);
+                }
+            }
+        }
     }
 
     @Override // from SystemService
diff --git a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
index b1f6f80..5b1074f 100644
--- a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
+++ b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
@@ -26,7 +26,9 @@
 import android.os.RemoteException;
 import android.service.translation.TranslationServiceInfo;
 import android.util.Slog;
+import android.view.autofill.AutofillId;
 import android.view.translation.TranslationSpec;
+import android.view.translation.UiTranslationManager.UiTranslationState;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.IResultReceiver;
@@ -34,6 +36,7 @@
 import com.android.server.infra.AbstractPerUserSystemService;
 
 import java.util.ArrayList;
+import java.util.List;
 
 final class TranslationManagerServiceImpl extends
         AbstractPerUserSystemService<TranslationManagerServiceImpl, TranslationManagerService> {
@@ -122,4 +125,11 @@
             remoteService.onSessionCreated(sourceSpec, destSpec, sessionId, resultReceiver);
         }
     }
+
+    @GuardedBy("mLock")
+    public void updateUiTranslationState(@UiTranslationState int state,
+            TranslationSpec sourceSpec, TranslationSpec destSpec, List<AutofillId> viewIds,
+            int taskId) {
+        // TODO: implement this in next change
+    }
 }
diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java
index fd462c2..bfb159f 100644
--- a/services/usage/java/com/android/server/usage/IntervalStats.java
+++ b/services/usage/java/com/android/server/usage/IntervalStats.java
@@ -54,6 +54,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.IOException;
+import java.util.Arrays;
 import java.util.List;
 
 public class IntervalStats {
@@ -459,13 +460,14 @@
      */
     private boolean deobfuscateUsageStats(PackagesTokenData packagesTokenData) {
         boolean dataOmitted = false;
+        final ArraySet<Integer> omittedTokens = new ArraySet<>();
         final int usageStatsSize = packageStatsObfuscated.size();
         for (int statsIndex = 0; statsIndex < usageStatsSize; statsIndex++) {
             final int packageToken = packageStatsObfuscated.keyAt(statsIndex);
             final UsageStats usageStats = packageStatsObfuscated.valueAt(statsIndex);
             usageStats.mPackageName = packagesTokenData.getPackageString(packageToken);
             if (usageStats.mPackageName == null) {
-                Slog.e(TAG, "Unable to parse usage stats package " + packageToken);
+                omittedTokens.add(packageToken);
                 dataOmitted = true;
                 continue;
             }
@@ -477,8 +479,6 @@
                 final int actionToken = usageStats.mChooserCountsObfuscated.keyAt(actionIndex);
                 final String action = packagesTokenData.getString(packageToken, actionToken);
                 if (action == null) {
-                    Slog.i(TAG, "Unable to parse chooser action " + actionToken
-                            + " for package " + packageToken);
                     continue;
                 }
                 final SparseIntArray categoryCounts =
@@ -489,8 +489,6 @@
                     final String category = packagesTokenData.getString(packageToken,
                             categoryToken);
                     if (category == null) {
-                        Slog.i(TAG, "Unable to parse chooser category " + categoryToken
-                                + " for package " + packageToken);
                         continue;
                     }
                     categoryCountsMap.put(category, categoryCounts.valueAt(categoryIndex));
@@ -499,6 +497,10 @@
             }
             packageStats.put(usageStats.mPackageName, usageStats);
         }
+        if (dataOmitted) {
+            Slog.d(TAG, "Unable to parse usage stats packages: "
+                    + Arrays.toString(omittedTokens.toArray()));
+        }
         return dataOmitted;
     }
 
@@ -511,12 +513,13 @@
      */
     private boolean deobfuscateEvents(PackagesTokenData packagesTokenData) {
         boolean dataOmitted = false;
+        final ArraySet<Integer> omittedTokens = new ArraySet<>();
         for (int i = this.events.size() - 1; i >= 0; i--) {
             final Event event = this.events.get(i);
             final int packageToken = event.mPackageToken;
             event.mPackage = packagesTokenData.getPackageString(packageToken);
             if (event.mPackage == null) {
-                Slog.e(TAG, "Unable to parse event package " + packageToken);
+                omittedTokens.add(packageToken);
                 this.events.remove(i);
                 dataOmitted = true;
                 continue;
@@ -524,26 +527,14 @@
 
             if (event.mClassToken != PackagesTokenData.UNASSIGNED_TOKEN) {
                 event.mClass = packagesTokenData.getString(packageToken, event.mClassToken);
-                if (event.mClass == null) {
-                    Slog.i(TAG, "Unable to parse class " + event.mClassToken
-                            + " for package " + packageToken);
-                }
             }
             if (event.mTaskRootPackageToken != PackagesTokenData.UNASSIGNED_TOKEN) {
                 event.mTaskRootPackage = packagesTokenData.getString(packageToken,
                         event.mTaskRootPackageToken);
-                if (event.mTaskRootPackage == null) {
-                    Slog.i(TAG, "Unable to parse task root package " + event.mTaskRootPackageToken
-                            + " for package " + packageToken);
-                }
             }
             if (event.mTaskRootClassToken != PackagesTokenData.UNASSIGNED_TOKEN) {
                 event.mTaskRootClass = packagesTokenData.getString(packageToken,
                         event.mTaskRootClassToken);
-                if (event.mTaskRootClass == null) {
-                    Slog.i(TAG, "Unable to parse task root class " + event.mTaskRootClassToken
-                            + " for package " + packageToken);
-                }
             }
             switch (event.mEventType) {
                 case CONFIGURATION_CHANGE:
@@ -555,7 +546,7 @@
                     event.mShortcutId = packagesTokenData.getString(packageToken,
                             event.mShortcutIdToken);
                     if (event.mShortcutId == null) {
-                        Slog.e(TAG, "Unable to parse shortcut " + event.mShortcutIdToken
+                        Slog.v(TAG, "Unable to parse shortcut " + event.mShortcutIdToken
                                 + " for package " + packageToken);
                         this.events.remove(i);
                         dataOmitted = true;
@@ -566,7 +557,7 @@
                     event.mNotificationChannelId = packagesTokenData.getString(packageToken,
                             event.mNotificationChannelIdToken);
                     if (event.mNotificationChannelId == null) {
-                        Slog.e(TAG, "Unable to parse notification channel "
+                        Slog.v(TAG, "Unable to parse notification channel "
                                 + event.mNotificationChannelIdToken + " for package "
                                 + packageToken);
                         this.events.remove(i);
@@ -577,7 +568,7 @@
                 case LOCUS_ID_SET:
                     event.mLocusId = packagesTokenData.getString(packageToken, event.mLocusIdToken);
                     if (event.mLocusId == null) {
-                        Slog.e(TAG, "Unable to parse locus " + event.mLocusIdToken
+                        Slog.v(TAG, "Unable to parse locus " + event.mLocusIdToken
                                 + " for package " + packageToken);
                         this.events.remove(i);
                         dataOmitted = true;
@@ -586,6 +577,10 @@
                     break;
             }
         }
+        if (dataOmitted) {
+            Slog.d(TAG, "Unable to parse event packages: "
+                    + Arrays.toString(omittedTokens.toArray()));
+        }
         return dataOmitted;
     }
 
diff --git a/services/usage/java/com/android/server/usage/PackagesTokenData.java b/services/usage/java/com/android/server/usage/PackagesTokenData.java
index f19abbb..272daf4 100644
--- a/services/usage/java/com/android/server/usage/PackagesTokenData.java
+++ b/services/usage/java/com/android/server/usage/PackagesTokenData.java
@@ -16,6 +16,7 @@
 package com.android.server.usage;
 
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
 
@@ -56,6 +57,11 @@
      * Stores a map of packages that were removed and when they were removed.
      */
     public final ArrayMap<String, Long> removedPackagesMap = new ArrayMap<>();
+    /**
+     * Stores a set of removed package tokens. This is solely for dump purposes when comparing
+     * parsing errors to recently removed packages.
+     */
+    public final ArraySet<Integer> removedPackageTokens = new ArraySet<>();
 
     public PackagesTokenData() {
     }
@@ -174,6 +180,7 @@
         final int packageToken = packagesToTokensMap.get(packageName).get(packageName);
         packagesToTokensMap.remove(packageName);
         tokensToPackagesMap.delete(packageToken);
+        removedPackageTokens.add(packageToken);
         return packageToken;
     }
 }
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index 52b0afb..a0a3909 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -514,6 +514,7 @@
         res.codeBytes = stats.codeSize + stats.externalCodeSize;
         res.dataBytes = stats.dataSize + stats.externalDataSize;
         res.cacheBytes = stats.cacheSize + stats.externalCacheSize;
+        res.externalCacheBytes = stats.externalCacheSize;
         return res;
     }
 
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index 9d48955..a4f5249 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -53,6 +53,7 @@
 import java.nio.file.Files;
 import java.nio.file.StandardCopyOption;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 
@@ -1500,6 +1501,10 @@
             pw.increaseIndent();
             pw.println("Counter: " + mPackagesTokenData.counter);
             pw.println("Tokens Map Size: " + mPackagesTokenData.tokensToPackagesMap.size());
+            if (!mPackagesTokenData.removedPackageTokens.isEmpty()) {
+                pw.println("Removed Package Tokens: "
+                        + Arrays.toString(mPackagesTokenData.removedPackageTokens.toArray()));
+            }
             for (int i = 0; i < mPackagesTokenData.tokensToPackagesMap.size(); i++) {
                 final int packageToken = mPackagesTokenData.tokensToPackagesMap.keyAt(i);
                 final String packageStrings = String.join(", ",
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index f1bea67..717040a 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -18,6 +18,7 @@
 
 import static android.Manifest.permission.MODIFY_PHONE_STATE;
 
+import android.Manifest;
 import android.annotation.ElapsedRealtimeLong;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
@@ -109,6 +110,20 @@
  */
 public abstract class Connection extends Conferenceable {
 
+    /**@hide*/
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "STATE_", value = {
+            STATE_INITIALIZING,
+            STATE_NEW,
+            STATE_RINGING,
+            STATE_DIALING,
+            STATE_ACTIVE,
+            STATE_HOLDING,
+            STATE_DISCONNECTED,
+            STATE_PULLING_CALL
+    })
+    public @interface ConnectionState {}
+
     /**
      * The connection is initializing. This is generally the first state for a {@code Connection}
      * returned by a {@link ConnectionService}.
@@ -3343,6 +3358,24 @@
      */
     public void handleRttUpgradeResponse(@Nullable RttTextStream rttTextStream) {}
 
+    /**
+     * Indicates that call filtering in Telecom is complete
+     *
+     * This method is called for a connection created via
+     * {@link ConnectionService#onCreateIncomingConnection} when call filtering completes in
+     * Telecom, including checking the blocked number db, per-contact settings, and custom call
+     * filtering apps.
+     *
+     * @param isBlocked {@code true} if the call was blocked, {@code false} otherwise. If this is
+     *                  {@code true}, {@link #onDisconnect()} will be called soon after
+     *                  this is called.
+     * @param isInContacts Indicates whether the caller is in the user's contacts list.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.READ_CONTACTS)
+    public void onCallFilteringCompleted(boolean isBlocked, boolean isInContacts) { }
+
     static String toLogSafePhoneNumber(String number) {
         // For unknown number, log empty string.
         if (number == null) {
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index b1ccb53..f86f9d5 100755
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -147,6 +147,7 @@
     private static final String SESSION_POST_DIAL_CONT = "CS.oPDC";
     private static final String SESSION_PULL_EXTERNAL_CALL = "CS.pEC";
     private static final String SESSION_SEND_CALL_EVENT = "CS.sCE";
+    private static final String SESSION_CALL_FILTERING_COMPLETED = "CS.oCFC";
     private static final String SESSION_HANDOVER_COMPLETE = "CS.hC";
     private static final String SESSION_EXTRAS_CHANGED = "CS.oEC";
     private static final String SESSION_START_RTT = "CS.+RTT";
@@ -200,6 +201,7 @@
     private static final int MSG_ADD_PARTICIPANT = 39;
     private static final int MSG_EXPLICIT_CALL_TRANSFER = 40;
     private static final int MSG_EXPLICIT_CALL_TRANSFER_CONSULTATIVE = 41;
+    private static final int MSG_ON_CALL_FILTERING_COMPLETED = 42;
 
     private static Connection sNullConnection;
 
@@ -722,6 +724,22 @@
         }
 
         @Override
+        public void onCallFilteringCompleted(String callId, boolean isBlocked, boolean isInContacts,
+                Session.Info sessionInfo) {
+            Log.startSession(sessionInfo, SESSION_CALL_FILTERING_COMPLETED);
+            try {
+                SomeArgs args = SomeArgs.obtain();
+                args.arg1 = callId;
+                args.arg2 = isBlocked;
+                args.arg3 = isInContacts;
+                args.arg4 = Log.createSubsession();
+                mHandler.obtainMessage(MSG_ON_CALL_FILTERING_COMPLETED, args).sendToTarget();
+            } finally {
+                Log.endSession();
+            }
+        }
+
+        @Override
         public void onExtrasChanged(String callId, Bundle extras, Session.Info sessionInfo) {
             Log.startSession(sessionInfo, SESSION_EXTRAS_CHANGED);
             try {
@@ -1354,6 +1372,21 @@
                     }
                     break;
                 }
+                case MSG_ON_CALL_FILTERING_COMPLETED: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        Log.continueSession((Session) args.arg4,
+                                SESSION_HANDLER + SESSION_CALL_FILTERING_COMPLETED);
+                        String callId = (String) args.arg1;
+                        boolean isBlocked = (boolean) args.arg2;
+                        boolean isInContacts = (boolean) args.arg3;
+                        onCallFilteringCompleted(callId, isBlocked, isInContacts);
+                    } finally {
+                        args.recycle();
+                        Log.endSession();
+                    }
+                    break;
+                }
                 case MSG_HANDOVER_COMPLETE: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     try {
@@ -2345,6 +2378,14 @@
         }
     }
 
+    private void onCallFilteringCompleted(String callId, boolean isBlocked, boolean isInContacts) {
+        Log.i(this, "onCallFilteringCompleted(%s, %b, %b)", isBlocked, isInContacts);
+        Connection connection = findConnectionForAction(callId, "onCallFilteringCompleted");
+        if (connection != null) {
+            connection.onCallFilteringCompleted(isBlocked, isInContacts);
+        }
+    }
+
     /**
      * Notifies a {@link Connection} that a handover has completed.
      *
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index 52210a5..feb2ca5 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -16,8 +16,10 @@
 
 package android.telecom;
 
+import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.hardware.camera2.CameraManager;
 import android.net.Uri;
@@ -1198,6 +1200,28 @@
     }
 
     /**
+     * Notifies this {@link RemoteConnection} that call filtering has completed, as well as
+     * the results of a contacts lookup for the remote party.
+     * @param isBlocked Whether call filtering indicates that the call should be blocked
+     * @param isInContacts Whether the remote party is in the user's contacts
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.READ_CONTACTS)
+    public void onCallFilteringCompleted(boolean isBlocked, boolean isInContacts) {
+        Log.startSession("RC.oCFC", getActiveOwnerInfo());
+        try {
+            if (mConnected) {
+                mConnectionService.onCallFilteringCompleted(mConnectionId, isBlocked, isInContacts,
+                        null /*Session.Info*/);
+            }
+        } catch (RemoteException ignored) {
+        } finally {
+            Log.endSession();
+        }
+    }
+
+    /**
      * Notifies this {@link RemoteConnection} of a response to a previous remotely-initiated RTT
      * upgrade request sent via {@link Connection#sendRemoteRttRequest}.
      * Acceptance of the request is indicated by the supplied {@link RttTextStream} being non-null,
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index fb54179..92264be 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -118,6 +118,9 @@
 
     void sendCallEvent(String callId, String event, in Bundle extras, in Session.Info sessionInfo);
 
+    void onCallFilteringCompleted(String callId, boolean isBlocked, boolean isInContacts,
+            in Session.Info sessionInfo);
+
     void onExtrasChanged(String callId, in Bundle extras, in Session.Info sessionInfo);
 
     void startRtt(String callId, in ParcelFileDescriptor fromInCall,
diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java
index d012971..f6d18fc 100644
--- a/telephony/java/android/telephony/AccessNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -18,10 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.SystemApi;
-import android.hardware.radio.V1_1.GeranBands;
 import android.hardware.radio.V1_5.AccessNetwork;
-import android.hardware.radio.V1_5.EutranBands;
-import android.hardware.radio.V1_5.UtranBands;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -117,52 +114,120 @@
      * http://www.etsi.org/deliver/etsi_ts/145000_145099/145005/14.00.00_60/ts_145005v140000p.pdf
      */
     public static final class GeranBand {
-        public static final int BAND_T380 = GeranBands.BAND_T380;
-        public static final int BAND_T410 = GeranBands.BAND_T410;
-        public static final int BAND_450 = GeranBands.BAND_450;
-        public static final int BAND_480 = GeranBands.BAND_480;
-        public static final int BAND_710 = GeranBands.BAND_710;
-        public static final int BAND_750 = GeranBands.BAND_750;
-        public static final int BAND_T810 = GeranBands.BAND_T810;
-        public static final int BAND_850 = GeranBands.BAND_850;
-        public static final int BAND_P900 = GeranBands.BAND_P900;
-        public static final int BAND_E900 = GeranBands.BAND_E900;
-        public static final int BAND_R900 = GeranBands.BAND_R900;
-        public static final int BAND_DCS1800 = GeranBands.BAND_DCS1800;
-        public static final int BAND_PCS1900 = GeranBands.BAND_PCS1900;
-        public static final int BAND_ER900 = GeranBands.BAND_ER900;
+        public static final int BAND_T380 = android.hardware.radio.V1_1.GeranBands.BAND_T380;
+        public static final int BAND_T410 = android.hardware.radio.V1_1.GeranBands.BAND_T410;
+        public static final int BAND_450 = android.hardware.radio.V1_1.GeranBands.BAND_450;
+        public static final int BAND_480 = android.hardware.radio.V1_1.GeranBands.BAND_480;
+        public static final int BAND_710 = android.hardware.radio.V1_1.GeranBands.BAND_710;
+        public static final int BAND_750 = android.hardware.radio.V1_1.GeranBands.BAND_750;
+        public static final int BAND_T810 = android.hardware.radio.V1_1.GeranBands.BAND_T810;
+        public static final int BAND_850 = android.hardware.radio.V1_1.GeranBands.BAND_850;
+        public static final int BAND_P900 = android.hardware.radio.V1_1.GeranBands.BAND_P900;
+        public static final int BAND_E900 = android.hardware.radio.V1_1.GeranBands.BAND_E900;
+        public static final int BAND_R900 = android.hardware.radio.V1_1.GeranBands.BAND_R900;
+        public static final int BAND_DCS1800 = android.hardware.radio.V1_1.GeranBands.BAND_DCS1800;
+        public static final int BAND_PCS1900 = android.hardware.radio.V1_1.GeranBands.BAND_PCS1900;
+        public static final int BAND_ER900 = android.hardware.radio.V1_1.GeranBands.BAND_ER900;
+
+        /**
+         * GeranBand
+         *
+         * @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(prefix = {"BAND_"},
+                value = {BAND_T380,
+                        BAND_T410,
+                        BAND_450,
+                        BAND_480,
+                        BAND_710,
+                        BAND_750,
+                        BAND_T810,
+                        BAND_850,
+                        BAND_P900,
+                        BAND_E900,
+                        BAND_R900,
+                        BAND_DCS1800,
+                        BAND_PCS1900,
+                        BAND_ER900})
+
+        public @interface GeranBands {}
 
         /** @hide */
         private GeranBand() {}
     }
 
     /**
+     * 3GPP TS 45.005 Table 2-1 Dynamically mapped ARFCN.
+     * 3GPP TS 45.005 Table 2-2 Fixed designation of ARFCN.
+     * @hide
+     */
+    enum GeranBandArfcnFrequency {
+
+        // Dynamically mapped ARFCN
+//        GERAN_ARFCN_FREQUENCY_BAND_T380(GeranBand.BAND_T380, 380.2, 0),
+//        GERAN_ARFCN_FREQUENCY_BAND_T410(GeranBand.BAND_T410, 410.2, 0),
+//        GERAN_ARFCN_FREQUENCY_BAND_710(GeranBand.BAND_710, 698, 0),
+//        GERAN_ARFCN_FREQUENCY_BAND_750(GeranBand.BAND_750, 747, 438, 30),
+//        GERAN_ARFCN_FREQUENCY_BAND_T810(GeranBand.BAND_T810, 806, 350),
+        // Fixed designation of ARFCN
+        GERAN_ARFCN_FREQUENCY_BAND_450(GeranBand.BAND_450, 450600, 259, 259, 293, 10),
+        GERAN_ARFCN_FREQUENCY_BAND_480(GeranBand.BAND_480, 479000, 306, 306, 340, 10),
+        GERAN_ARFCN_FREQUENCY_BAND_850(GeranBand.BAND_850, 824200, 128, 128, 251, 45),
+        GERAN_ARFCN_FREQUENCY_BAND_DCS1800(GeranBand.BAND_DCS1800, 1710200, 512, 512, 885, 95),
+        GERAN_ARFCN_FREQUENCY_BAND_PCS1900(GeranBand.BAND_PCS1900, 1850200, 512, 512, 810, 80),
+        GERAN_ARFCN_FREQUENCY_BAND_E900_1(GeranBand.BAND_E900, 890000, 0, 0, 124, 45),
+        GERAN_ARFCN_FREQUENCY_BAND_E900_2(GeranBand.BAND_E900, 890000, 1024, 975, 1023, 45),
+        GERAN_ARFCN_FREQUENCY_BAND_R900_1(GeranBand.BAND_R900, 890000, 0, 0, 124, 45),
+        GERAN_ARFCN_FREQUENCY_BAND_R900_2(GeranBand.BAND_R900, 890000, 1024, 955, 1023, 45),
+        GERAN_ARFCN_FREQUENCY_BAND_P900(GeranBand.BAND_P900, 890000, 0, 1, 124, 45),
+        GERAN_ARFCN_FREQUENCY_BAND_ER900_1(GeranBand.BAND_ER900, 890000, 0, 0, 124, 45),
+        GERAN_ARFCN_FREQUENCY_BAND_ER900_2(GeranBand.BAND_ER900, 890000, 1024, 940, 1023, 1024);
+
+        GeranBandArfcnFrequency(int band, int uplinkFrequencyFirstKhz, int arfcnOffset,
+                                int arfcnRangeFirst, int arfcnRangeLast, int downlinkOffset) {
+            this.band = band;
+            this.uplinkFrequencyFirst = uplinkFrequencyFirstKhz;
+            this.arfcnOffset = arfcnOffset;
+            this.arfcnRangeFirst = arfcnRangeFirst;
+            this.arfcnRangeLast = arfcnRangeLast;
+            this.downlinkOffset = downlinkOffset;
+        }
+
+        int band;
+        int uplinkFrequencyFirst;
+        int arfcnOffset;
+        int arfcnRangeFirst;
+        int arfcnRangeLast;
+        int downlinkOffset;
+    }
+
+    /**
      * Frequency bands for UTRAN.
      * http://www.etsi.org/deliver/etsi_ts/125100_125199/125104/13.03.00_60/ts_125104v130p.pdf
      */
     public static final class UtranBand {
-        public static final int BAND_1 = UtranBands.BAND_1;
-        public static final int BAND_2 = UtranBands.BAND_2;
-        public static final int BAND_3 = UtranBands.BAND_3;
-        public static final int BAND_4 = UtranBands.BAND_4;
-        public static final int BAND_5 = UtranBands.BAND_5;
-        public static final int BAND_6 = UtranBands.BAND_6;
-        public static final int BAND_7 = UtranBands.BAND_7;
-        public static final int BAND_8 = UtranBands.BAND_8;
-        public static final int BAND_9 = UtranBands.BAND_9;
-        public static final int BAND_10 = UtranBands.BAND_10;
-        public static final int BAND_11 = UtranBands.BAND_11;
-        public static final int BAND_12 = UtranBands.BAND_12;
-        public static final int BAND_13 = UtranBands.BAND_13;
-        public static final int BAND_14 = UtranBands.BAND_14;
+        public static final int BAND_1 = android.hardware.radio.V1_5.UtranBands.BAND_1;
+        public static final int BAND_2 = android.hardware.radio.V1_5.UtranBands.BAND_2;
+        public static final int BAND_3 = android.hardware.radio.V1_5.UtranBands.BAND_3;
+        public static final int BAND_4 = android.hardware.radio.V1_5.UtranBands.BAND_4;
+        public static final int BAND_5 = android.hardware.radio.V1_5.UtranBands.BAND_5;
+        public static final int BAND_6 = android.hardware.radio.V1_5.UtranBands.BAND_6;
+        public static final int BAND_7 = android.hardware.radio.V1_5.UtranBands.BAND_7;
+        public static final int BAND_8 = android.hardware.radio.V1_5.UtranBands.BAND_8;
+        public static final int BAND_9 = android.hardware.radio.V1_5.UtranBands.BAND_9;
+        public static final int BAND_10 = android.hardware.radio.V1_5.UtranBands.BAND_10;
+        public static final int BAND_11 = android.hardware.radio.V1_5.UtranBands.BAND_11;
+        public static final int BAND_12 = android.hardware.radio.V1_5.UtranBands.BAND_12;
+        public static final int BAND_13 = android.hardware.radio.V1_5.UtranBands.BAND_13;
+        public static final int BAND_14 = android.hardware.radio.V1_5.UtranBands.BAND_14;
         // band 15, 16, 17, 18 are reserved
-        public static final int BAND_19 = UtranBands.BAND_19;
-        public static final int BAND_20 = UtranBands.BAND_20;
-        public static final int BAND_21 = UtranBands.BAND_21;
-        public static final int BAND_22 = UtranBands.BAND_22;
+        public static final int BAND_19 = android.hardware.radio.V1_5.UtranBands.BAND_19;
+        public static final int BAND_20 = android.hardware.radio.V1_5.UtranBands.BAND_20;
+        public static final int BAND_21 = android.hardware.radio.V1_5.UtranBands.BAND_21;
+        public static final int BAND_22 = android.hardware.radio.V1_5.UtranBands.BAND_22;
         // band 23, 24 are reserved
-        public static final int BAND_25 = UtranBands.BAND_25;
-        public static final int BAND_26 = UtranBands.BAND_26;
+        public static final int BAND_25 = android.hardware.radio.V1_5.UtranBands.BAND_25;
+        public static final int BAND_26 = android.hardware.radio.V1_5.UtranBands.BAND_26;
 
         // Frequency bands for TD-SCDMA. Defined in 3GPP TS 25.102, Table 5.2.
 
@@ -171,115 +236,423 @@
          * 1900 - 1920 MHz: Uplink and downlink transmission
          * 2010 - 2025 MHz: Uplink and downlink transmission
          */
-        public static final int BAND_A = UtranBands.BAND_A;
+        public static final int BAND_A = android.hardware.radio.V1_5.UtranBands.BAND_A;
 
         /**
          * Band B
          * 1850 - 1910 MHz: Uplink and downlink transmission
          * 1930 - 1990 MHz: Uplink and downlink transmission
          */
-        public static final int BAND_B = UtranBands.BAND_B;
+        public static final int BAND_B = android.hardware.radio.V1_5.UtranBands.BAND_B;
 
         /**
          * Band C
          * 1910 - 1930 MHz: Uplink and downlink transmission
          */
-        public static final int BAND_C = UtranBands.BAND_C;
+        public static final int BAND_C = android.hardware.radio.V1_5.UtranBands.BAND_C;
 
         /**
          * Band D
          * 2570 - 2620 MHz: Uplink and downlink transmission
          */
-        public static final int BAND_D = UtranBands.BAND_D;
+        public static final int BAND_D = android.hardware.radio.V1_5.UtranBands.BAND_D;
 
         /**
          * Band E
          * 2300—2400 MHz: Uplink and downlink transmission
          */
-        public static final int BAND_E = UtranBands.BAND_E;
+        public static final int BAND_E = android.hardware.radio.V1_5.UtranBands.BAND_E;
 
         /**
          * Band F
          * 1880 - 1920 MHz: Uplink and downlink transmission
          */
-        public static final int BAND_F = UtranBands.BAND_F;
+        public static final int BAND_F = android.hardware.radio.V1_5.UtranBands.BAND_F;
+
+        /**
+         * UtranBand
+         *
+         * @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(prefix = {"BAND_"},
+                value = {BAND_1,
+                        BAND_2,
+                        BAND_3,
+                        BAND_4,
+                        BAND_5,
+                        BAND_6,
+                        BAND_7,
+                        BAND_8,
+                        BAND_9,
+                        BAND_10,
+                        BAND_11,
+                        BAND_12,
+                        BAND_13,
+                        BAND_14,
+                        BAND_19,
+                        BAND_20,
+                        BAND_21,
+                        BAND_22,
+                        BAND_25,
+                        BAND_26,
+                        BAND_A,
+                        BAND_B,
+                        BAND_C,
+                        BAND_D,
+                        BAND_E,
+                        BAND_F})
+
+        public @interface UtranBands {}
 
         /** @hide */
         private UtranBand() {}
     }
 
     /**
+     * 3GPP TS 25.101, Table 5.1 UARFCN definition (general)
+     * 3GPP TS 25.102, Table 5.2 UTRA Absolute Radio Frequency Channel Number 1.28 Mcps TDD Option.
+     *
+     * @hide
+     */
+    enum UtranBandArfcnFrequency {
+
+        UTRAN_ARFCN_FREQUENCY_BAND_1(UtranBand.BAND_1, 0, 10562, 10838, 0, 9612, 9888),
+        UTRAN_ARFCN_FREQUENCY_BAND_2(UtranBand.BAND_2, 0, 9662, 9938, 0, 9262, 9538),
+        UTRAN_ARFCN_FREQUENCY_BAND_3(UtranBand.BAND_3, 1575000, 1162, 1513, 1525000, 937, 1288),
+        UTRAN_ARFCN_FREQUENCY_BAND_4(UtranBand.BAND_4, 1805000, 1537, 1738, 1450000, 1312, 1513),
+        UTRAN_ARFCN_FREQUENCY_BAND_5(UtranBand.BAND_5, 0, 4357, 4458, 0, 4132, 4233),
+        UTRAN_ARFCN_FREQUENCY_BAND_6(UtranBand.BAND_6, 0, 4387, 4413, 0, 4162, 4188),
+        UTRAN_ARFCN_FREQUENCY_BAND_7(UtranBand.BAND_7, 2175000, 2237, 2563, 2100000, 2012, 2338),
+        UTRAN_ARFCN_FREQUENCY_BAND_8(UtranBand.BAND_8, 340000, 2937, 3088, 340000, 2712, 2863),
+        UTRAN_ARFCN_FREQUENCY_BAND_9(UtranBand.BAND_9, 0, 9327, 9837, 0, 8762, 8912),
+        UTRAN_ARFCN_FREQUENCY_BAND_10(UtranBand.BAND_10, 1490000, 3112, 3388, 1135000, 2887, 3163),
+        UTRAN_ARFCN_FREQUENCY_BAND_11(UtranBand.BAND_11, 736000, 3712, 3787, 733000, 3487, 3562),
+        UTRAN_ARFCN_FREQUENCY_BAND_12(UtranBand.BAND_12, -37000, 3842, 3903, -22000, 3617, 3678),
+        UTRAN_ARFCN_FREQUENCY_BAND_13(UtranBand.BAND_13, -55000, 4017, 4043, 21000, 3792, 3818),
+        UTRAN_ARFCN_FREQUENCY_BAND_14(UtranBand.BAND_14, -63000, 4117, 4143, 12000, 3892, 3918),
+        UTRAN_ARFCN_FREQUENCY_BAND_19(UtranBand.BAND_19, 735000, 712, 763, 770000, 312, 363),
+        UTRAN_ARFCN_FREQUENCY_BAND_20(UtranBand.BAND_20, -109000, 4512, 4638, -23000, 4287, 4413),
+        UTRAN_ARFCN_FREQUENCY_BAND_21(UtranBand.BAND_21, 1326000, 862, 912, 1358000, 462, 512),
+        UTRAN_ARFCN_FREQUENCY_BAND_22(UtranBand.BAND_22, 2580000, 4662, 5038, 2525000, 4437, 4813),
+        UTRAN_ARFCN_FREQUENCY_BAND_25(UtranBand.BAND_25, 910000, 5112, 5413, 875000, 4887, 5188),
+        UTRAN_ARFCN_FREQUENCY_BAND_A(UtranBand.BAND_A, 0, 10054, 10121, 0, 9504, 9596),
+        UTRAN_ARFCN_FREQUENCY_BAND_B(UtranBand.BAND_B, 0, 9654, 9946, 0, 9254, 9546),
+        UTRAN_ARFCN_FREQUENCY_BAND_C(UtranBand.BAND_C, 0, 0, 0, 0, 9554, 9646),
+        UTRAN_ARFCN_FREQUENCY_BAND_D(UtranBand.BAND_D, 0, 0, 0, 0, 12854, 13096),
+        UTRAN_ARFCN_FREQUENCY_BAND_E(UtranBand.BAND_E, 0, 0, 0, 0, 11504, 11996),
+        UTRAN_ARFCN_FREQUENCY_BAND_F(UtranBand.BAND_F, 0, 0, 0, 0, 9404, 9596);
+
+        UtranBandArfcnFrequency(int band, int downlinkOffsetKhz, int downlinkRangeFirst,
+                                int downlinkRangeLast, int uplinkOffsetKhz, int uplinkRangeFirst,
+                                int uplinkRangeLast) {
+            this.band = band;
+            this.downlinkOffset = downlinkOffsetKhz;
+            this.downlinkRangeFirst = downlinkRangeFirst;
+            this.downlinkRangeLast = downlinkRangeLast;
+            this.uplinkOffset = uplinkOffsetKhz;
+            this.uplinkRangeFirst = uplinkRangeFirst;
+            this.uplinkRangeLast = uplinkRangeLast;
+        }
+
+        int band;
+        int downlinkOffset;
+        int downlinkRangeFirst;
+        int downlinkRangeLast;
+        int uplinkOffset;
+        int uplinkRangeFirst;
+        int uplinkRangeLast;
+    }
+
+    /**
      * Frequency bands for EUTRAN.
      * 3GPP TS 36.101, Version 16.4.0, Table 5.5: Operating bands
      * https://www.etsi.org/deliver/etsi_ts/136100_136199/136101/15.09.00_60/ts_136101v150900p.pdf
      */
     public static final class EutranBand {
-        public static final int BAND_1 = EutranBands.BAND_1;
-        public static final int BAND_2 = EutranBands.BAND_2;
-        public static final int BAND_3 = EutranBands.BAND_3;
-        public static final int BAND_4 = EutranBands.BAND_4;
-        public static final int BAND_5 = EutranBands.BAND_5;
-        public static final int BAND_6 = EutranBands.BAND_6;
-        public static final int BAND_7 = EutranBands.BAND_7;
-        public static final int BAND_8 = EutranBands.BAND_8;
-        public static final int BAND_9 = EutranBands.BAND_9;
-        public static final int BAND_10 = EutranBands.BAND_10;
-        public static final int BAND_11 = EutranBands.BAND_11;
-        public static final int BAND_12 = EutranBands.BAND_12;
-        public static final int BAND_13 = EutranBands.BAND_13;
-        public static final int BAND_14 = EutranBands.BAND_14;
-        public static final int BAND_17 = EutranBands.BAND_17;
-        public static final int BAND_18 = EutranBands.BAND_18;
-        public static final int BAND_19 = EutranBands.BAND_19;
-        public static final int BAND_20 = EutranBands.BAND_20;
-        public static final int BAND_21 = EutranBands.BAND_21;
-        public static final int BAND_22 = EutranBands.BAND_22;
-        public static final int BAND_23 = EutranBands.BAND_23;
-        public static final int BAND_24 = EutranBands.BAND_24;
-        public static final int BAND_25 = EutranBands.BAND_25;
-        public static final int BAND_26 = EutranBands.BAND_26;
-        public static final int BAND_27 = EutranBands.BAND_27;
-        public static final int BAND_28 = EutranBands.BAND_28;
-        public static final int BAND_30 = EutranBands.BAND_30;
-        public static final int BAND_31 = EutranBands.BAND_31;
-        public static final int BAND_33 = EutranBands.BAND_33;
-        public static final int BAND_34 = EutranBands.BAND_34;
-        public static final int BAND_35 = EutranBands.BAND_35;
-        public static final int BAND_36 = EutranBands.BAND_36;
-        public static final int BAND_37 = EutranBands.BAND_37;
-        public static final int BAND_38 = EutranBands.BAND_38;
-        public static final int BAND_39 = EutranBands.BAND_39;
-        public static final int BAND_40 = EutranBands.BAND_40;
-        public static final int BAND_41 = EutranBands.BAND_41;
-        public static final int BAND_42 = EutranBands.BAND_42;
-        public static final int BAND_43 = EutranBands.BAND_43;
-        public static final int BAND_44 = EutranBands.BAND_44;
-        public static final int BAND_45 = EutranBands.BAND_45;
-        public static final int BAND_46 = EutranBands.BAND_46;
-        public static final int BAND_47 = EutranBands.BAND_47;
-        public static final int BAND_48 = EutranBands.BAND_48;
-        public static final int BAND_49 = EutranBands.BAND_49;
-        public static final int BAND_50 = EutranBands.BAND_50;
-        public static final int BAND_51 = EutranBands.BAND_51;
-        public static final int BAND_52 = EutranBands.BAND_52;
-        public static final int BAND_53 = EutranBands.BAND_53;
-        public static final int BAND_65 = EutranBands.BAND_65;
-        public static final int BAND_66 = EutranBands.BAND_66;
-        public static final int BAND_68 = EutranBands.BAND_68;
-        public static final int BAND_70 = EutranBands.BAND_70;
-        public static final int BAND_71 = EutranBands.BAND_71;
-        public static final int BAND_72 = EutranBands.BAND_72;
-        public static final int BAND_73 = EutranBands.BAND_73;
-        public static final int BAND_74 = EutranBands.BAND_74;
-        public static final int BAND_85 = EutranBands.BAND_85;
-        public static final int BAND_87 = EutranBands.BAND_87;
-        public static final int BAND_88 = EutranBands.BAND_88;
+        public static final int BAND_1 = android.hardware.radio.V1_5.EutranBands.BAND_1;
+        public static final int BAND_2 = android.hardware.radio.V1_5.EutranBands.BAND_2;
+        public static final int BAND_3 = android.hardware.radio.V1_5.EutranBands.BAND_3;
+        public static final int BAND_4 = android.hardware.radio.V1_5.EutranBands.BAND_4;
+        public static final int BAND_5 = android.hardware.radio.V1_5.EutranBands.BAND_5;
+        public static final int BAND_6 = android.hardware.radio.V1_5.EutranBands.BAND_6;
+        public static final int BAND_7 = android.hardware.radio.V1_5.EutranBands.BAND_7;
+        public static final int BAND_8 = android.hardware.radio.V1_5.EutranBands.BAND_8;
+        public static final int BAND_9 = android.hardware.radio.V1_5.EutranBands.BAND_9;
+        public static final int BAND_10 = android.hardware.radio.V1_5.EutranBands.BAND_10;
+        public static final int BAND_11 = android.hardware.radio.V1_5.EutranBands.BAND_11;
+        public static final int BAND_12 = android.hardware.radio.V1_5.EutranBands.BAND_12;
+        public static final int BAND_13 = android.hardware.radio.V1_5.EutranBands.BAND_13;
+        public static final int BAND_14 = android.hardware.radio.V1_5.EutranBands.BAND_14;
+        public static final int BAND_17 = android.hardware.radio.V1_5.EutranBands.BAND_17;
+        public static final int BAND_18 = android.hardware.radio.V1_5.EutranBands.BAND_18;
+        public static final int BAND_19 = android.hardware.radio.V1_5.EutranBands.BAND_19;
+        public static final int BAND_20 = android.hardware.radio.V1_5.EutranBands.BAND_20;
+        public static final int BAND_21 = android.hardware.radio.V1_5.EutranBands.BAND_21;
+        public static final int BAND_22 = android.hardware.radio.V1_5.EutranBands.BAND_22;
+        public static final int BAND_23 = android.hardware.radio.V1_5.EutranBands.BAND_23;
+        public static final int BAND_24 = android.hardware.radio.V1_5.EutranBands.BAND_24;
+        public static final int BAND_25 = android.hardware.radio.V1_5.EutranBands.BAND_25;
+        public static final int BAND_26 = android.hardware.radio.V1_5.EutranBands.BAND_26;
+        public static final int BAND_27 = android.hardware.radio.V1_5.EutranBands.BAND_27;
+        public static final int BAND_28 = android.hardware.radio.V1_5.EutranBands.BAND_28;
+        public static final int BAND_30 = android.hardware.radio.V1_5.EutranBands.BAND_30;
+        public static final int BAND_31 = android.hardware.radio.V1_5.EutranBands.BAND_31;
+        public static final int BAND_33 = android.hardware.radio.V1_5.EutranBands.BAND_33;
+        public static final int BAND_34 = android.hardware.radio.V1_5.EutranBands.BAND_34;
+        public static final int BAND_35 = android.hardware.radio.V1_5.EutranBands.BAND_35;
+        public static final int BAND_36 = android.hardware.radio.V1_5.EutranBands.BAND_36;
+        public static final int BAND_37 = android.hardware.radio.V1_5.EutranBands.BAND_37;
+        public static final int BAND_38 = android.hardware.radio.V1_5.EutranBands.BAND_38;
+        public static final int BAND_39 = android.hardware.radio.V1_5.EutranBands.BAND_39;
+        public static final int BAND_40 = android.hardware.radio.V1_5.EutranBands.BAND_40;
+        public static final int BAND_41 = android.hardware.radio.V1_5.EutranBands.BAND_41;
+        public static final int BAND_42 = android.hardware.radio.V1_5.EutranBands.BAND_42;
+        public static final int BAND_43 = android.hardware.radio.V1_5.EutranBands.BAND_43;
+        public static final int BAND_44 = android.hardware.radio.V1_5.EutranBands.BAND_44;
+        public static final int BAND_45 = android.hardware.radio.V1_5.EutranBands.BAND_45;
+        public static final int BAND_46 = android.hardware.radio.V1_5.EutranBands.BAND_46;
+        public static final int BAND_47 = android.hardware.radio.V1_5.EutranBands.BAND_47;
+        public static final int BAND_48 = android.hardware.radio.V1_5.EutranBands.BAND_48;
+        public static final int BAND_49 = android.hardware.radio.V1_5.EutranBands.BAND_49;
+        public static final int BAND_50 = android.hardware.radio.V1_5.EutranBands.BAND_50;
+        public static final int BAND_51 = android.hardware.radio.V1_5.EutranBands.BAND_51;
+        public static final int BAND_52 = android.hardware.radio.V1_5.EutranBands.BAND_52;
+        public static final int BAND_53 = android.hardware.radio.V1_5.EutranBands.BAND_53;
+        public static final int BAND_65 = android.hardware.radio.V1_5.EutranBands.BAND_65;
+        public static final int BAND_66 = android.hardware.radio.V1_5.EutranBands.BAND_66;
+        public static final int BAND_68 = android.hardware.radio.V1_5.EutranBands.BAND_68;
+        public static final int BAND_70 = android.hardware.radio.V1_5.EutranBands.BAND_70;
+        public static final int BAND_71 = android.hardware.radio.V1_5.EutranBands.BAND_71;
+        public static final int BAND_72 = android.hardware.radio.V1_5.EutranBands.BAND_72;
+        public static final int BAND_73 = android.hardware.radio.V1_5.EutranBands.BAND_73;
+        public static final int BAND_74 = android.hardware.radio.V1_5.EutranBands.BAND_74;
+        public static final int BAND_85 = android.hardware.radio.V1_5.EutranBands.BAND_85;
+        public static final int BAND_87 = android.hardware.radio.V1_5.EutranBands.BAND_87;
+        public static final int BAND_88 = android.hardware.radio.V1_5.EutranBands.BAND_88;
+
+        /**
+         * EutranBands
+         *
+         * @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(prefix = {"BAND_"},
+                value = {BAND_1,
+                        BAND_2,
+                        BAND_3,
+                        BAND_4,
+                        BAND_5,
+                        BAND_6,
+                        BAND_7,
+                        BAND_8,
+                        BAND_9,
+                        BAND_10,
+                        BAND_11,
+                        BAND_12,
+                        BAND_13,
+                        BAND_14,
+                        BAND_17,
+                        BAND_18,
+                        BAND_19,
+                        BAND_20,
+                        BAND_21,
+                        BAND_22,
+                        BAND_23,
+                        BAND_24,
+                        BAND_25,
+                        BAND_26,
+                        BAND_27,
+                        BAND_28,
+                        BAND_30,
+                        BAND_31,
+                        BAND_33,
+                        BAND_34,
+                        BAND_35,
+                        BAND_36,
+                        BAND_37,
+                        BAND_38,
+                        BAND_39,
+                        BAND_40,
+                        BAND_41,
+                        BAND_42,
+                        BAND_43,
+                        BAND_44,
+                        BAND_45,
+                        BAND_46,
+                        BAND_47,
+                        BAND_48,
+                        BAND_49,
+                        BAND_50,
+                        BAND_51,
+                        BAND_52,
+                        BAND_53,
+                        BAND_65,
+                        BAND_66,
+                        BAND_68,
+                        BAND_70,
+                        BAND_71,
+                        BAND_72,
+                        BAND_73,
+                        BAND_74,
+                        BAND_85,
+                        BAND_87,
+                        BAND_88})
+
+        public @interface EutranBands {}
 
         /** @hide */
         private EutranBand() {};
     }
 
     /**
+     * 3GPP TS 36.101 Table 5.7.3-1 E-UTRA channel numbers.
+     *
+     * @hide
+     */
+    enum EutranBandArfcnFrequency {
+
+        EUTRAN_ARFCN_FREQUENCY_BAND_1(
+                EutranBand.BAND_1, 2110000, 0, 599, 1920000, 18800, 18599),
+        EUTRAN_ARFCN_FREQUENCY_BAND_2(
+                EutranBand.BAND_2, 1930000, 600, 1199, 1850000, 18600, 19199),
+        EUTRAN_ARFCN_FREQUENCY_BAND_3(
+                EutranBand.BAND_3, 1805000, 1200, 1949, 1710000, 19200, 19949),
+        EUTRAN_ARFCN_FREQUENCY_BAND_4(
+                EutranBand.BAND_4, 2110000, 1950, 2399, 1710000, 19950, 20399),
+        EUTRAN_ARFCN_FREQUENCY_BAND_5(
+                EutranBand.BAND_5, 869000, 2400, 2649, 824000, 20400, 20649),
+        EUTRAN_ARFCN_FREQUENCY_BAND_6(
+                EutranBand.BAND_6, 875000, 2650, 2749, 830000, 20650, 20749),
+        EUTRAN_ARFCN_FREQUENCY_BAND_7(
+                EutranBand.BAND_7, 2620000, 2750, 3449, 2500000, 20750, 21449),
+        EUTRAN_ARFCN_FREQUENCY_BAND_8(
+                EutranBand.BAND_8, 925000, 3450, 3799, 880000, 21450, 21799),
+        EUTRAN_ARFCN_FREQUENCY_BAND_9(
+                EutranBand.BAND_9, 1844900, 3800, 4149, 1749900, 21800, 22149),
+        EUTRAN_ARFCN_FREQUENCY_BAND_10(
+                EutranBand.BAND_10, 2110000, 4150, 4749, 1710000, 22150, 22749),
+        EUTRAN_ARFCN_FREQUENCY_BAND_11(
+                EutranBand.BAND_11, 1475900, 4750, 4949, 1427900, 22750, 22949),
+        EUTRAN_ARFCN_FREQUENCY_BAND_12(
+                EutranBand.BAND_12, 729000, 5010, 5179, 699000, 23010, 23179),
+        EUTRAN_ARFCN_FREQUENCY_BAND_13(
+                EutranBand.BAND_13, 746000, 5180, 5279, 777000, 23180, 23279),
+        EUTRAN_ARFCN_FREQUENCY_BAND_14(
+                EutranBand.BAND_14, 758000, 5280, 5379, 788000, 23230, 23379),
+        EUTRAN_ARFCN_FREQUENCY_BAND_17(
+                EutranBand.BAND_17, 734000, 5730, 5849, 704000, 23730, 23849),
+        EUTRAN_ARFCN_FREQUENCY_BAND_18(
+                EutranBand.BAND_18, 860000, 5850, 5999, 815000, 23850, 23999),
+        EUTRAN_ARFCN_FREQUENCY_BAND_19(
+                EutranBand.BAND_19, 875000, 6000, 6149, 830000, 24000, 24149),
+        EUTRAN_ARFCN_FREQUENCY_BAND_20(
+                EutranBand.BAND_20, 791000, 6150, 6449, 832000, 24150, 24449),
+        EUTRAN_ARFCN_FREQUENCY_BAND_21(
+                EutranBand.BAND_21, 1495900, 6450, 6599, 1447900, 24450, 24599),
+        EUTRAN_ARFCN_FREQUENCY_BAND_22(
+                EutranBand.BAND_22, 3510000, 6600, 7399, 3410000, 24600, 25399),
+        EUTRAN_ARFCN_FREQUENCY_BAND_23(
+                EutranBand.BAND_23, 2180000, 7500, 7699, 2000000, 25500, 25699),
+        EUTRAN_ARFCN_FREQUENCY_BAND_24(
+                EutranBand.BAND_24, 1525000, 7700, 8039, 1626500, 25700, 26039),
+        EUTRAN_ARFCN_FREQUENCY_BAND_25(
+                EutranBand.BAND_25, 1930000, 8040, 8689, 1850000, 26040, 26689),
+        EUTRAN_ARFCN_FREQUENCY_BAND_26(
+                EutranBand.BAND_26, 859000, 8690, 9039, 814000, 26690, 27039),
+        EUTRAN_ARFCN_FREQUENCY_BAND_27(
+                EutranBand.BAND_27, 852000, 9040, 9209, 807000, 27040, 27209),
+        EUTRAN_ARFCN_FREQUENCY_BAND_28(
+                EutranBand.BAND_28, 758000, 9210, 9659, 703000, 27210, 27659),
+        EUTRAN_ARFCN_FREQUENCY_BAND_30(
+                EutranBand.BAND_30, 2350000, 9770, 9869, 2305000, 27660, 27759),
+        EUTRAN_ARFCN_FREQUENCY_BAND_31(
+                EutranBand.BAND_31, 462500, 9870, 9919, 452500, 27760, 27809),
+        EUTRAN_ARFCN_FREQUENCY_BAND_33(
+                EutranBand.BAND_33, 1900000, 36000, 36199, 1900000, 36000, 36199),
+        EUTRAN_ARFCN_FREQUENCY_BAND_34(
+                EutranBand.BAND_34, 2010000, 36200, 36349, 2010000, 36200, 36349),
+        EUTRAN_ARFCN_FREQUENCY_BAND_35(
+                EutranBand.BAND_35, 1850000, 36350, 36949, 1850000, 36350, 36949),
+        EUTRAN_ARFCN_FREQUENCY_BAND_36(
+                EutranBand.BAND_36, 1930000, 36950, 37549, 1930000, 36950, 37549),
+        EUTRAN_ARFCN_FREQUENCY_BAND_37(
+                EutranBand.BAND_37, 1910000, 37550, 37749, 1910000, 37550, 37749),
+        EUTRAN_ARFCN_FREQUENCY_BAND_38(
+                EutranBand.BAND_38, 2570000, 37750, 38249, 2570000, 37750, 38249),
+        EUTRAN_ARFCN_FREQUENCY_BAND_39(
+                EutranBand.BAND_39, 1880000, 38250, 38649, 1880000, 38250, 38649),
+        EUTRAN_ARFCN_FREQUENCY_BAND_40(
+                EutranBand.BAND_40, 2300000, 38650, 39649, 2300000, 38650, 39649),
+        EUTRAN_ARFCN_FREQUENCY_BAND_41(
+                EutranBand.BAND_41, 2496000, 39650, 41589, 2496000, 39650, 41589),
+        EUTRAN_ARFCN_FREQUENCY_BAND_42(
+                EutranBand.BAND_42, 3400000, 41950, 43589, 3400000, 41950, 43589),
+        EUTRAN_ARFCN_FREQUENCY_BAND_43(
+                EutranBand.BAND_43, 3600000, 43950, 45589, 3600000, 43950, 45589),
+        EUTRAN_ARFCN_FREQUENCY_BAND_44(
+                EutranBand.BAND_44, 703000, 45590, 46589, 703000, 45590, 46589),
+        EUTRAN_ARFCN_FREQUENCY_BAND_45(
+                EutranBand.BAND_45, 1447000, 46590, 46789, 1447000, 46590, 46789),
+        EUTRAN_ARFCN_FREQUENCY_BAND_46(
+                EutranBand.BAND_46, 5150000, 46790, 54539, 5150000, 46790, 54539),
+        EUTRAN_ARFCN_FREQUENCY_BAND_47(
+                EutranBand.BAND_47, 5855000, 54540, 55239, 5855000, 54540, 55239),
+        EUTRAN_ARFCN_FREQUENCY_BAND_48(
+                EutranBand.BAND_48, 3550000, 55240, 56739, 3550000, 55240, 56739),
+        EUTRAN_ARFCN_FREQUENCY_BAND_49(
+                EutranBand.BAND_49, 3550000, 56740, 58239, 3550000, 56740, 58239),
+        EUTRAN_ARFCN_FREQUENCY_BAND_50(
+                EutranBand.BAND_50, 1432000, 58240, 59089, 1432000, 58240, 59089),
+        EUTRAN_ARFCN_FREQUENCY_BAND_51(
+                EutranBand.BAND_51, 1427000, 59090, 59139, 1427000, 59090, 59139),
+        EUTRAN_ARFCN_FREQUENCY_BAND_52(
+                EutranBand.BAND_52, 3300000, 59140, 60139, 3300000, 59140, 60139),
+        EUTRAN_ARFCN_FREQUENCY_BAND_53(
+                EutranBand.BAND_53, 2483500, 60140, 60254, 2483500, 60140, 60254),
+        EUTRAN_ARFCN_FREQUENCY_BAND_65(
+                EutranBand.BAND_65, 2110000, 65536, 66435, 1920000, 131072, 131971),
+        EUTRAN_ARFCN_FREQUENCY_BAND_66(
+                EutranBand.BAND_66, 2110000, 66436, 67335, 1710000, 131972, 132671),
+        EUTRAN_ARFCN_FREQUENCY_BAND_68(
+                EutranBand.BAND_68, 753000, 67536, 67835, 698000, 132672, 132971),
+        EUTRAN_ARFCN_FREQUENCY_BAND_70(
+                EutranBand.BAND_70, 1995000, 68336, 68585, 1695000, 132972, 133121),
+        EUTRAN_ARFCN_FREQUENCY_BAND_71(
+                EutranBand.BAND_71, 617000, 68586, 68935, 663000, 133122, 133471),
+        EUTRAN_ARFCN_FREQUENCY_BAND_72(
+                EutranBand.BAND_72, 461000, 68936, 68985, 451000, 133472, 133521),
+        EUTRAN_ARFCN_FREQUENCY_BAND_73(
+                EutranBand.BAND_73, 460000, 68986, 69035, 450000, 133522, 133571),
+        EUTRAN_ARFCN_FREQUENCY_BAND_74(
+                EutranBand.BAND_74, 1475000, 69036, 69465, 1427000, 133572, 134001),
+        EUTRAN_ARFCN_FREQUENCY_BAND_85(
+                EutranBand.BAND_85, 728000, 70366, 70545, 698000, 134002, 134181),
+        EUTRAN_ARFCN_FREQUENCY_BAND_87(
+                EutranBand.BAND_87, 420000, 70546, 70595, 410000, 134182, 134231),
+        EUTRAN_ARFCN_FREQUENCY_BAND_88(
+                EutranBand.BAND_88, 422000, 70596, 70645, 412000, 134231, 134280);
+
+        EutranBandArfcnFrequency(int band, int downlinkLowKhz, int downlinkOffset,
+                                 int downlinkRange, int uplinkLowKhz, int uplinkOffset,
+                                 int uplinkRange) {
+            this.band = band;
+            this.downlinkLowKhz = downlinkLowKhz;
+            this.downlinkOffset = downlinkOffset;
+            this.uplinkLowKhz = uplinkLowKhz;
+            this.uplinkOffset = uplinkOffset;
+            this.downlinkRange = downlinkRange;
+            this.uplinkRange = uplinkRange;
+        }
+
+        int band;
+        int downlinkLowKhz;
+        int downlinkOffset;
+        int uplinkLowKhz;
+        int uplinkOffset;
+        int downlinkRange;
+        int uplinkRange;
+    }
+
+    /**
      * Frequency bands for CDMA2000.
      * http://www.3gpp2.org/Public_html/Specs/C.S0057-E_v1.0_Bandclass_Specification.pdf
      * @hide
@@ -320,7 +693,7 @@
      * https://www.etsi.org/deliver/etsi_ts/138100_138199/13810102/15.08.00_60/ts_13810102v150800p.pdf
      */
     public static final class NgranBands {
-        /** 3GPP TS 38.101-1, Version 16.2.0, Table 5.2-1: FR1 bands */
+        /** 3GPP TS 38.101-1, Version 16.5.0, Table 5.2-1: FR1 bands */
         public static final int BAND_1 = android.hardware.radio.V1_5.NgranBands.BAND_1;
         public static final int BAND_2 = android.hardware.radio.V1_5.NgranBands.BAND_2;
         public static final int BAND_3 = android.hardware.radio.V1_5.NgranBands.BAND_3;
@@ -332,6 +705,7 @@
         public static final int BAND_18 = android.hardware.radio.V1_5.NgranBands.BAND_18;
         public static final int BAND_20 = android.hardware.radio.V1_5.NgranBands.BAND_20;
         public static final int BAND_25 = android.hardware.radio.V1_5.NgranBands.BAND_25;
+        public static final int BAND_26 = android.hardware.radio.V1_6.NgranBands.BAND_26;
         public static final int BAND_28 = android.hardware.radio.V1_5.NgranBands.BAND_28;
         public static final int BAND_29 = android.hardware.radio.V1_5.NgranBands.BAND_29;
         public static final int BAND_30 = android.hardware.radio.V1_5.NgranBands.BAND_30;
@@ -340,9 +714,11 @@
         public static final int BAND_39 = android.hardware.radio.V1_5.NgranBands.BAND_39;
         public static final int BAND_40 = android.hardware.radio.V1_5.NgranBands.BAND_40;
         public static final int BAND_41 = android.hardware.radio.V1_5.NgranBands.BAND_41;
+        public static final int BAND_46 = android.hardware.radio.V1_6.NgranBands.BAND_46;
         public static final int BAND_48 = android.hardware.radio.V1_5.NgranBands.BAND_48;
         public static final int BAND_50 = android.hardware.radio.V1_5.NgranBands.BAND_50;
         public static final int BAND_51 = android.hardware.radio.V1_5.NgranBands.BAND_51;
+        public static final int BAND_53 = android.hardware.radio.V1_6.NgranBands.BAND_53;
         public static final int BAND_65 = android.hardware.radio.V1_5.NgranBands.BAND_65;
         public static final int BAND_66 = android.hardware.radio.V1_5.NgranBands.BAND_66;
         public static final int BAND_70 = android.hardware.radio.V1_5.NgranBands.BAND_70;
@@ -366,6 +742,7 @@
         public static final int BAND_93 = android.hardware.radio.V1_5.NgranBands.BAND_93;
         public static final int BAND_94 = android.hardware.radio.V1_5.NgranBands.BAND_94;
         public static final int BAND_95 = android.hardware.radio.V1_5.NgranBands.BAND_95;
+        public static final int BAND_96 = android.hardware.radio.V1_6.NgranBands.BAND_96;
 
         /** 3GPP TS 38.101-2, Version 16.2.0, Table 5.2-1: FR2 bands */
         public static final int BAND_257 = android.hardware.radio.V1_5.NgranBands.BAND_257;
@@ -390,6 +767,7 @@
                         BAND_18,
                         BAND_20,
                         BAND_25,
+                        BAND_26,
                         BAND_28,
                         BAND_29,
                         BAND_30,
@@ -398,9 +776,11 @@
                         BAND_39,
                         BAND_40,
                         BAND_41,
+                        BAND_46,
                         BAND_48,
                         BAND_50,
                         BAND_51,
+                        BAND_53,
                         BAND_65,
                         BAND_66,
                         BAND_70,
@@ -424,6 +804,7 @@
                         BAND_93,
                         BAND_94,
                         BAND_95,
+                        BAND_96,
                         BAND_257,
                         BAND_258,
                         BAND_260,
@@ -464,7 +845,8 @@
                 value = {
                         FREQUENCY_RANGE_GROUP_UNKNOWN,
                         FREQUENCY_RANGE_GROUP_1,
-                        FREQUENCY_RANGE_GROUP_2})
+                        FREQUENCY_RANGE_GROUP_2
+                })
         public @interface FrequencyRangeGroup {}
 
         /**
@@ -489,6 +871,7 @@
                 case BAND_18:
                 case BAND_20:
                 case BAND_25:
+                case BAND_26:
                 case BAND_28:
                 case BAND_29:
                 case BAND_30:
@@ -497,9 +880,11 @@
                 case BAND_39:
                 case BAND_40:
                 case BAND_41:
+                case BAND_46:
                 case BAND_48:
                 case BAND_50:
                 case BAND_51:
+                case BAND_53:
                 case BAND_65:
                 case BAND_66:
                 case BAND_70:
@@ -523,6 +908,7 @@
                 case BAND_93:
                 case BAND_94:
                 case BAND_95:
+                case BAND_96:
                     return FREQUENCY_RANGE_GROUP_1;
                 case BAND_257:
                 case BAND_258:
@@ -538,6 +924,33 @@
         private NgranBands() {}
     }
 
+    /**
+     * 3GPP TS 38.104 Table 5.4.2.1-1 NR-ARFCN parameters for the global frequency raster.
+     *
+     * @hide
+     */
+    enum NgranArfcnFrequency {
+
+        NGRAN_ARFCN_FREQUENCY_RANGE_1(5, 0, 0, 0, 599999),
+        NGRAN_ARFCN_FREQUENCY_RANGE_2(15, 3000000, 600000, 600000, 2016666),
+        NGRAN_ARFCN_FREQUENCY_RANGE_3(60, 24250080, 2016667, 2016667, 3279165);
+
+        NgranArfcnFrequency(int globalKhz, int rangeOffset, int arfcnOffset,
+                            int rangeFirst, int rangeLast) {
+            this.globalKhz = globalKhz;
+            this.rangeOffset = rangeOffset;
+            this.arfcnOffset = arfcnOffset;
+            this.rangeFirst = rangeFirst;
+            this.rangeLast = rangeLast;
+        }
+
+        int globalKhz;
+        int rangeOffset;
+        int arfcnOffset;
+        int rangeFirst;
+        int rangeLast;
+    }
+
     /** @hide */
     private AccessNetworkConstants() {};
 }
diff --git a/telephony/java/android/telephony/AccessNetworkUtils.java b/telephony/java/android/telephony/AccessNetworkUtils.java
index 7661a32..f29f3bd 100644
--- a/telephony/java/android/telephony/AccessNetworkUtils.java
+++ b/telephony/java/android/telephony/AccessNetworkUtils.java
@@ -4,12 +4,20 @@
 import static android.telephony.ServiceState.DUPLEX_MODE_TDD;
 import static android.telephony.ServiceState.DUPLEX_MODE_UNKNOWN;
 
+import android.telephony.AccessNetworkConstants.EutranBandArfcnFrequency;
 import android.telephony.AccessNetworkConstants.EutranBand;
 import android.telephony.AccessNetworkConstants.GeranBand;
+import android.telephony.AccessNetworkConstants.GeranBandArfcnFrequency;
+import android.telephony.AccessNetworkConstants.NgranArfcnFrequency;
+import android.telephony.AccessNetworkConstants.NgranBands;
 import android.telephony.AccessNetworkConstants.UtranBand;
+import android.telephony.AccessNetworkConstants.UtranBandArfcnFrequency;
 import android.telephony.ServiceState.DuplexMode;
+import android.util.Log;
 
 import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
 
 /**
  * Utilities to map between radio constants.
@@ -22,9 +30,27 @@
     private AccessNetworkUtils() {}
 
     public static final int INVALID_BAND = -1;
+    public static final int INVALID_FREQUENCY = -1;
 
     /** ISO country code of Japan. */
     private static final String JAPAN_ISO_COUNTRY_CODE = "jp";
+    private static final String TAG = "AccessNetworkUtils";
+
+    private static final int FREQUENCY_KHZ = 1000;
+    private static final int FREQUENCY_RANGE_LOW_KHZ = 1000000;
+    private static final int FREQUENCY_RANGE_MID_KHZ = 3000000;
+    private static final int FREQUENCY_RANGE_HIGH_KHZ = 6000000;
+
+    private static final Set<Integer> UARFCN_NOT_GENERAL_BAND;
+    static {
+        UARFCN_NOT_GENERAL_BAND = new HashSet<Integer>();
+        UARFCN_NOT_GENERAL_BAND.add(UtranBand.BAND_A);
+        UARFCN_NOT_GENERAL_BAND.add(UtranBand.BAND_B);
+        UARFCN_NOT_GENERAL_BAND.add(UtranBand.BAND_C);
+        UARFCN_NOT_GENERAL_BAND.add(UtranBand.BAND_D);
+        UARFCN_NOT_GENERAL_BAND.add(UtranBand.BAND_E);
+        UARFCN_NOT_GENERAL_BAND.add(UtranBand.BAND_F);
+    }
 
     /**
      * Gets the duplex mode for the given EUTRAN operating band.
@@ -325,4 +351,403 @@
         }
         return INVALID_BAND;
     }
+
+    /**
+     * Get geran bands from {@link PhysicalChannelConfig#getBand()}
+     */
+    public static int getFrequencyRangeGroupFromGeranBand(@GeranBand.GeranBands int band) {
+        switch (band) {
+            case GeranBand.BAND_T380:
+            case GeranBand.BAND_T410:
+            case GeranBand.BAND_450:
+            case GeranBand.BAND_480:
+            case GeranBand.BAND_710:
+            case GeranBand.BAND_750:
+            case GeranBand.BAND_T810:
+            case GeranBand.BAND_850:
+            case GeranBand.BAND_P900:
+            case GeranBand.BAND_E900:
+            case GeranBand.BAND_R900:
+            case GeranBand.BAND_ER900:
+                return ServiceState.FREQUENCY_RANGE_LOW;
+            case GeranBand.BAND_DCS1800:
+            case GeranBand.BAND_PCS1900:
+                return ServiceState.FREQUENCY_RANGE_MID;
+            default:
+                return ServiceState.FREQUENCY_RANGE_UNKNOWN;
+        }
+    }
+
+    /**
+     * Get utran bands from {@link PhysicalChannelConfig#getBand()}
+     */
+    public static int getFrequencyRangeGroupFromUtranBand(@UtranBand.UtranBands int band) {
+        switch (band) {
+            case UtranBand.BAND_5:
+            case UtranBand.BAND_6:
+            case UtranBand.BAND_8:
+            case UtranBand.BAND_12:
+            case UtranBand.BAND_13:
+            case UtranBand.BAND_14:
+            case UtranBand.BAND_19:
+            case UtranBand.BAND_20:
+            case UtranBand.BAND_26:
+                return ServiceState.FREQUENCY_RANGE_LOW;
+            case UtranBand.BAND_1:
+            case UtranBand.BAND_2:
+            case UtranBand.BAND_3:
+            case UtranBand.BAND_4:
+            case UtranBand.BAND_7:
+            case UtranBand.BAND_9:
+            case UtranBand.BAND_10:
+            case UtranBand.BAND_11:
+            case UtranBand.BAND_21:
+            case UtranBand.BAND_25:
+            case UtranBand.BAND_A:
+            case UtranBand.BAND_B:
+            case UtranBand.BAND_C:
+            case UtranBand.BAND_D:
+            case UtranBand.BAND_E:
+            case UtranBand.BAND_F:
+                return ServiceState.FREQUENCY_RANGE_MID;
+            case UtranBand.BAND_22:
+                return ServiceState.FREQUENCY_RANGE_HIGH;
+            default:
+                return ServiceState.FREQUENCY_RANGE_UNKNOWN;
+        }
+    }
+
+    /**
+     * Get eutran bands from {@link PhysicalChannelConfig#getBand()}
+     * 3GPP TS 36.101 Table 5.5 EUTRA operating bands
+     */
+    public static int getFrequencyRangeGroupFromEutranBand(@EutranBand.EutranBands int band) {
+        switch (band) {
+            case EutranBand.BAND_5:
+            case EutranBand.BAND_6:
+            case EutranBand.BAND_8:
+            case EutranBand.BAND_12:
+            case EutranBand.BAND_13:
+            case EutranBand.BAND_14:
+            case EutranBand.BAND_17:
+            case EutranBand.BAND_18:
+            case EutranBand.BAND_19:
+            case EutranBand.BAND_20:
+            case EutranBand.BAND_26:
+            case EutranBand.BAND_27:
+            case EutranBand.BAND_28:
+            case EutranBand.BAND_31:
+            case EutranBand.BAND_44:
+            case EutranBand.BAND_50:
+            case EutranBand.BAND_51:
+            case EutranBand.BAND_68:
+            case EutranBand.BAND_71:
+            case EutranBand.BAND_72:
+            case EutranBand.BAND_73:
+            case EutranBand.BAND_85:
+            case EutranBand.BAND_87:
+            case EutranBand.BAND_88:
+                return ServiceState.FREQUENCY_RANGE_LOW;
+            case EutranBand.BAND_1:
+            case EutranBand.BAND_2:
+            case EutranBand.BAND_3:
+            case EutranBand.BAND_4:
+            case EutranBand.BAND_7:
+            case EutranBand.BAND_9:
+            case EutranBand.BAND_10:
+            case EutranBand.BAND_11:
+            case EutranBand.BAND_21:
+            case EutranBand.BAND_23:
+            case EutranBand.BAND_24:
+            case EutranBand.BAND_25:
+            case EutranBand.BAND_30:
+            case EutranBand.BAND_33:
+            case EutranBand.BAND_34:
+            case EutranBand.BAND_35:
+            case EutranBand.BAND_36:
+            case EutranBand.BAND_37:
+            case EutranBand.BAND_38:
+            case EutranBand.BAND_39:
+            case EutranBand.BAND_40:
+            case EutranBand.BAND_41:
+            case EutranBand.BAND_45:
+            case EutranBand.BAND_53:
+            case EutranBand.BAND_65:
+            case EutranBand.BAND_66:
+            case EutranBand.BAND_70:
+            case EutranBand.BAND_74:
+                return ServiceState.FREQUENCY_RANGE_MID;
+            case EutranBand.BAND_22:
+            case EutranBand.BAND_42:
+            case EutranBand.BAND_43:
+            case EutranBand.BAND_46:
+            case EutranBand.BAND_47:
+            case EutranBand.BAND_48:
+            case EutranBand.BAND_49:
+            case EutranBand.BAND_52:
+                return ServiceState.FREQUENCY_RANGE_HIGH;
+            default:
+                return ServiceState.FREQUENCY_RANGE_UNKNOWN;
+        }
+    }
+
+    /**
+     * Get ngran band from {@link PhysicalChannelConfig#getBand()}
+     * 3GPP TS 38.104 Table 5.2-1 NR operating bands in FR1
+     * 3GPP TS 38.104 Table 5.2-2 NR operating bands in FR2
+     */
+    public static int getFrequencyRangeGroupFromNrBand(@NgranBands.NgranBand int band) {
+        switch (band) {
+            case NgranBands.BAND_5:
+            case NgranBands.BAND_8:
+            case NgranBands.BAND_12:
+            case NgranBands.BAND_14:
+            case NgranBands.BAND_18:
+            case NgranBands.BAND_20:
+            case NgranBands.BAND_26:
+            case NgranBands.BAND_28:
+            case NgranBands.BAND_29:
+            case NgranBands.BAND_71:
+            case NgranBands.BAND_81:
+            case NgranBands.BAND_82:
+            case NgranBands.BAND_83:
+            case NgranBands.BAND_89:
+                return ServiceState.FREQUENCY_RANGE_LOW;
+            case NgranBands.BAND_1:
+            case NgranBands.BAND_2:
+            case NgranBands.BAND_3:
+            case NgranBands.BAND_7:
+            case NgranBands.BAND_25:
+            case NgranBands.BAND_30:
+            case NgranBands.BAND_34:
+            case NgranBands.BAND_38:
+            case NgranBands.BAND_39:
+            case NgranBands.BAND_40:
+            case NgranBands.BAND_41:
+            case NgranBands.BAND_50:
+            case NgranBands.BAND_51:
+            case NgranBands.BAND_53:
+            case NgranBands.BAND_65:
+            case NgranBands.BAND_66:
+            case NgranBands.BAND_70:
+            case NgranBands.BAND_74:
+            case NgranBands.BAND_75:
+            case NgranBands.BAND_76:
+            case NgranBands.BAND_80:
+            case NgranBands.BAND_84:
+            case NgranBands.BAND_86:
+            case NgranBands.BAND_90:
+            case NgranBands.BAND_91:
+            case NgranBands.BAND_92:
+            case NgranBands.BAND_93:
+            case NgranBands.BAND_94:
+            case NgranBands.BAND_95:
+                return ServiceState.FREQUENCY_RANGE_MID;
+            case NgranBands.BAND_46:
+            case NgranBands.BAND_48:
+            case NgranBands.BAND_77:
+            case NgranBands.BAND_78:
+            case NgranBands.BAND_79:
+                return ServiceState.FREQUENCY_RANGE_HIGH;
+            case NgranBands.BAND_96:
+            case NgranBands.BAND_257:
+            case NgranBands.BAND_258:
+            case NgranBands.BAND_260:
+            case NgranBands.BAND_261:
+                return ServiceState.FREQUENCY_RANGE_MMWAVE;
+            default:
+                return ServiceState.FREQUENCY_RANGE_UNKNOWN;
+        }
+    }
+
+    /**
+     * 3GPP TS 38.104 Table 5.4.2.1-1 NR-ARFCN parameters for the global frequency raster.
+     * Formula of NR-ARFCN convert to actual frequency:
+     * Actual frequency(kHz) = (RANGE_OFFSET + GLOBAL_KHZ * (ARFCN - ARFCN_OFFSET))
+     */
+    public static int getFrequencyFromNrArfcn(int nrArfcn) {
+
+        int globalKhz = 0;
+        int rangeOffset = 0;
+        int arfcnOffset = 0;
+        for (NgranArfcnFrequency nrArfcnFrequency : AccessNetworkConstants.
+                NgranArfcnFrequency.values()) {
+            if (nrArfcn >= nrArfcnFrequency.rangeFirst
+                    && nrArfcn <= nrArfcnFrequency.rangeLast) {
+                globalKhz = nrArfcnFrequency.globalKhz;
+                rangeOffset = nrArfcnFrequency.rangeOffset;
+                arfcnOffset = nrArfcnFrequency.arfcnOffset;
+                break;
+            }
+        }
+        return rangeOffset + globalKhz * (nrArfcn - arfcnOffset);
+    }
+
+    /**
+     * Get actual frequency from E-UTRA ARFCN.
+     */
+    public static int getFrequencyFromEarfcn(int band, int earfcn, boolean isUplink) {
+
+        int low = 0;
+        int offset = 0;
+        for (EutranBandArfcnFrequency earfcnFrequency : EutranBandArfcnFrequency.values()) {
+            if (band == earfcnFrequency.band) {
+                if (isInEarfcnRange(earfcn, earfcnFrequency, isUplink)) {
+                    low = isUplink ? earfcnFrequency.uplinkLowKhz : earfcnFrequency.downlinkLowKhz;
+                    offset = isUplink ? earfcnFrequency.uplinkOffset
+                            : earfcnFrequency.downlinkOffset;
+                    break;
+                } else {
+                    Log.e(TAG, "Band and the range of EARFCN are not consistent.");
+                    return INVALID_FREQUENCY;
+                }
+            }
+        }
+        return convertEarfcnToFrequency(low, earfcn, offset);
+    }
+
+    /**
+     * 3GPP TS 36.101 Table 5.7.3-1 E-UTRA channel numbers.
+     * Formula of E-UTRA ARFCN convert to actual frequency:
+     * Actual frequency(kHz) = (DOWNLINK_LOW + 0.1 * (ARFCN - DOWNLINK_OFFSET)) * FREQUENCY_KHZ
+     * Actual frequency(kHz) = (UPLINK_LOW + 0.1 * (ARFCN - UPLINK_OFFSET)) * FREQUENCY_KHZ
+     */
+    private static int convertEarfcnToFrequency(int low, int earfcn, int offset) {
+        return low + 100 * (earfcn - offset);
+    }
+
+    private static boolean isInEarfcnRange(int earfcn, EutranBandArfcnFrequency earfcnFrequency,
+                                           boolean isUplink) {
+        if (isUplink) {
+            return earfcn >= earfcnFrequency.uplinkOffset && earfcn <= earfcnFrequency.uplinkRange;
+        } else {
+            return earfcn >= earfcnFrequency.downlinkOffset
+                    && earfcn <= earfcnFrequency.downlinkRange;
+        }
+    }
+
+    /**
+     * Get actual frequency from UTRA ARFCN.
+     */
+    public static int getFrequencyFromUarfcn(int band, int uarfcn, boolean isUplink) {
+
+        int offsetKhz = 0;
+        for (UtranBandArfcnFrequency uarfcnFrequency : AccessNetworkConstants.
+                UtranBandArfcnFrequency.values()) {
+            if (band == uarfcnFrequency.band) {
+                if (isInUarfcnRange(uarfcn, uarfcnFrequency, isUplink)) {
+                    offsetKhz = isUplink ? uarfcnFrequency.uplinkOffset
+                            : uarfcnFrequency.downlinkOffset;
+                    break;
+                } else {
+                    Log.e(TAG, "Band and the range of UARFCN are not consistent.");
+                    return INVALID_FREQUENCY;
+                }
+            }
+        }
+
+        if (!UARFCN_NOT_GENERAL_BAND.contains(band)) {
+            return convertUarfcnToFrequency(offsetKhz, uarfcn);
+        } else {
+            return convertUarfcnTddToFrequency(band, uarfcn);
+        }
+    }
+
+    /**
+     * 3GPP TS 25.101, Table 5.1 UARFCN definition (general).
+     * Formula of UTRA ARFCN convert to actual frequency:
+     * For general bands:
+     * Downlink actual frequency(kHz) = (DOWNLINK_OFFSET + 0.2 * ARFCN) * FREQUENCY_KHZ
+     * Uplink actual frequency(kHz) = (UPLINK_OFFSET + 0.2 * ARFCN) * FREQUENCY_KHZ
+     */
+    private static int convertUarfcnToFrequency(int offsetKhz, int uarfcn) {
+        return offsetKhz + (200 * uarfcn);
+    }
+
+    /**
+     * 3GPP TS 25.102, Table 5.2 UTRA Absolute Radio Frequency Channel Number 1.28 Mcps TDD Option.
+     * For FDD bands A, B, C, E, F:
+     * Actual frequency(kHz) =  5 * ARFCN * FREQUENCY_KHZ
+     * For TDD bands D:
+     * Actual frequency(kHz) =  (5 * (ARFCN - 2150.1MHz)) * FREQUENCY_KHZ
+     */
+    private static int convertUarfcnTddToFrequency(int band, int uarfcn) {
+        if (band != UtranBand.BAND_D) {
+            return 5 * uarfcn * FREQUENCY_KHZ;
+        } else {
+            return 5 * ((FREQUENCY_KHZ * uarfcn) - 2150100);
+        }
+    }
+
+    private static boolean isInUarfcnRange(int uarfcn, UtranBandArfcnFrequency uarfcnFrequency,
+                                           boolean isUplink) {
+        if (isUplink) {
+            return uarfcn >= uarfcnFrequency.uplinkRangeFirst
+                    && uarfcn <= uarfcnFrequency.uplinkRangeLast;
+        } else {
+            if (uarfcnFrequency.downlinkRangeFirst != 0 && uarfcnFrequency.downlinkRangeLast != 0) {
+                return uarfcn >= uarfcnFrequency.downlinkRangeFirst
+                        && uarfcn <= uarfcnFrequency.downlinkRangeLast;
+            } else {
+                // BAND_C, BAND_D, BAND_E and BAND_F do not have the downlink range.
+                return true;
+            }
+        }
+    }
+
+    /**
+     * Get actual frequency from GERAN ARFCN.
+     */
+    public static int getFrequencyFromArfcn(int band, int arfcn, boolean isUplink) {
+
+        int uplinkFrequencyFirst = 0;
+        int arfcnOffset = 0;
+        int downlinkOffset = 0;
+        int frequency = 0;
+        for (GeranBandArfcnFrequency arfcnFrequency : AccessNetworkConstants.
+                GeranBandArfcnFrequency.values()) {
+            if (band == arfcnFrequency.band) {
+                if (arfcn >= arfcnFrequency.arfcnRangeFirst
+                        && arfcn <= arfcnFrequency.arfcnRangeLast) {
+                    uplinkFrequencyFirst = arfcnFrequency.uplinkFrequencyFirst;
+                    downlinkOffset = arfcnFrequency.downlinkOffset;
+                    arfcnOffset = arfcnFrequency.arfcnOffset;
+                    frequency = convertArfcnToFrequency(arfcn, uplinkFrequencyFirst,
+                            arfcnOffset);
+                    break;
+                } else {
+                    Log.e(TAG, "Band and the range of ARFCN are not consistent.");
+                    return INVALID_FREQUENCY;
+                }
+            }
+        }
+
+        return isUplink ? frequency : frequency + downlinkOffset;
+    }
+
+    /**
+     * 3GPP TS 45.005 Table 2-1 Dynamically mapped ARFCN
+     * Formula of Geran ARFCN convert to actual frequency:
+     * Uplink actual frequency(kHz) =
+     *      (UPLINK_FREQUENCY_FIRST + 0.2 * (ARFCN - ARFCN_RANGE_FIRST)) * FREQUENCY_KHZ
+     * Downlink actual frequency(kHz) = Uplink actual frequency + 10
+     */
+    private static int convertArfcnToFrequency(int arfcn, int uplinkFrequencyFirstKhz,
+                                               int arfcnOffset) {
+        return uplinkFrequencyFirstKhz + 200 * (arfcn - arfcnOffset);
+    }
+
+    public static int getFrequencyRangeFromArfcn(int frequency) {
+        if (frequency < FREQUENCY_RANGE_LOW_KHZ) {
+            return ServiceState.FREQUENCY_RANGE_LOW;
+        } else if (frequency < FREQUENCY_RANGE_MID_KHZ
+                && frequency >= FREQUENCY_RANGE_LOW_KHZ) {
+            return ServiceState.FREQUENCY_RANGE_MID;
+        } else if (frequency < FREQUENCY_RANGE_HIGH_KHZ
+                && frequency >= FREQUENCY_RANGE_MID_KHZ) {
+            return ServiceState.FREQUENCY_RANGE_HIGH;
+        } else {
+            return ServiceState.FREQUENCY_RANGE_MMWAVE;
+        }
+    }
 }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 94fb812..daa3d1f0 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -4643,6 +4643,13 @@
      */
     public static final String KEY_USE_ACS_FOR_RCS_BOOL = "use_acs_for_rcs_bool";
 
+    /**
+     * Indicates temporarily unmetered mobile data is supported by the carrier.
+     * @hide
+     */
+    public static final String KEY_NETWORK_TEMP_NOT_METERED_SUPPORTED_BOOL =
+            "network_temp_not_metered_supported_bool";
+
     /** The default value for every variable. */
     private final static PersistableBundle sDefaults;
 
@@ -5193,6 +5200,7 @@
         sDefaults.putString(KEY_CALL_COMPOSER_PICTURE_SERVER_URL_STRING, "");
         sDefaults.putBoolean(KEY_USE_LOWER_MTU_VALUE_IF_BOTH_RECEIVED, false);
         sDefaults.putBoolean(KEY_USE_ACS_FOR_RCS_BOOL, false);
+        sDefaults.putBoolean(KEY_NETWORK_TEMP_NOT_METERED_SUPPORTED_BOOL, false);
     }
 
     /**
@@ -5211,9 +5219,25 @@
         public static final String KEY_HOTSPOT_MAX_CLIENT_COUNT =
                 KEY_PREFIX + "hotspot_maximum_client_count";
 
+        /**
+         * This configuration is intended to be a narrow exception for provisioning
+         * {@link android.net.wifi.WifiNetworkSuggestion} of widely-known carrier networks that do
+         * not support using randomized MAC address.
+         * Carrier provisioned {@link android.net.wifi.WifiNetworkSuggestion} with SSIDs included
+         * in this list will have MAC randomization disabled.
+         *
+         * Note: the SSIDs in the list are expected to be interpreted as is - do not add double
+         * quotes to the SSIDs.
+         */
+        public static final String KEY_SUGGESTION_SSID_LIST_WITH_MAC_RANDOMIZATION_DISABLED =
+                KEY_PREFIX + "suggestion_ssid_list_with_mac_randomization_disabled";
+
         private static PersistableBundle getDefaults() {
             PersistableBundle defaults = new PersistableBundle();
             defaults.putInt(KEY_HOTSPOT_MAX_CLIENT_COUNT, 0);
+            defaults.putStringArray(KEY_SUGGESTION_SSID_LIST_WITH_MAC_RANDOMIZATION_DISABLED,
+                    new String[0]);
+
             return defaults;
         }
 
diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java
index 95c69ba..b359ebe 100644
--- a/telephony/java/android/telephony/PhysicalChannelConfig.java
+++ b/telephony/java/android/telephony/PhysicalChannelConfig.java
@@ -19,7 +19,6 @@
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
-import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.telephony.Annotation.NetworkType;
@@ -56,6 +55,18 @@
     /** Physical Cell Id is unknown. */
     public static final int PHYSICAL_CELL_ID_UNKNOWN = -1;
 
+    /** Physical Cell Id's maximum value is 1007. */
+    public static final int PHYSICAL_CELL_ID_MAXIMUM_VALUE = 1007;
+
+    /** Cell bandwidth is unknown. */
+    public static final int CELL_BANDWIDTH_UNKNOWN = 0;
+
+    /** The frequency is unknown. */
+    public static final int FREQUENCY_UNKNOWN = -1;
+
+    /** The band is unknown. */
+    public static final int BAND_UNKNOWN = 0;
+
     /**
      * Connection status of the cell.
      *
@@ -65,15 +76,20 @@
     private int mCellConnectionStatus;
 
     /**
-     * Cell bandwidth, in kHz.
+     * Downlink cell bandwidth, in kHz.
      */
     private int mCellBandwidthDownlinkKhz;
 
     /**
+     * Uplink cell bandwidth, in kHz.
+     */
+    private int mCellBandwidthUplinkKhz;
+
+    /**
      * The radio technology for this physical channel.
      */
     @NetworkType
-    private int mRat;
+    private int mNetworkType;
 
     /**
      * The rough frequency range for this physical channel.
@@ -82,9 +98,24 @@
     private int mFrequencyRange;
 
     /**
-     * The absolute radio frequency channel number, {@link #CHANNEL_NUMBER_UNKNOWN} if unknown.
+     * The frequency of Downlink.
      */
-    private int mChannelNumber;
+    private int mDownlinkFrequency;
+
+    /**
+     * The frequency of Uplink.
+     */
+    private int mUplinkFrequency;
+
+    /**
+     * Downlink Absolute Radio Frequency Channel Number
+     */
+    private int mDownlinkChannelNumber;
+
+    /**
+     * Uplink Absolute Radio Frequency Channel Number
+     */
+    private int mUplinkChannelNumber;
 
     /**
      * A list of data calls mapped to this physical channel. An empty list means the physical
@@ -98,6 +129,11 @@
      */
     private int mPhysicalCellId;
 
+    /**
+     * This is the band which is being used.
+     */
+    private int mBand;
+
     @Override
     public int describeContents() {
         return 0;
@@ -107,27 +143,39 @@
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeInt(mCellConnectionStatus);
         dest.writeInt(mCellBandwidthDownlinkKhz);
-        dest.writeInt(mRat);
-        dest.writeInt(mChannelNumber);
+        dest.writeInt(mCellBandwidthUplinkKhz);
+        dest.writeInt(mNetworkType);
+        dest.writeInt(mDownlinkChannelNumber);
+        dest.writeInt(mUplinkChannelNumber);
         dest.writeInt(mFrequencyRange);
         dest.writeIntArray(mContextIds);
         dest.writeInt(mPhysicalCellId);
+        dest.writeInt(mBand);
     }
 
     /**
-     * @return Cell bandwidth, in kHz
+     * @return Downlink cell bandwidth in kHz, {@link #CELL_BANDWIDTH_UNKNOWN} if unknown.
      */
-    public int getCellBandwidthDownlink() {
+    @IntRange(from = 1)
+    public int getCellBandwidthDownlinkKhz() {
         return mCellBandwidthDownlinkKhz;
     }
 
     /**
+     * @return Uplink cell bandwidth in kHz, {@link #CELL_BANDWIDTH_UNKNOWN} if unknown.
+     */
+    @IntRange(from = 1)
+    public int getCellBandwidthUplinkKhz() {
+        return mCellBandwidthUplinkKhz;
+    }
+
+    /**
      * Get the list of data call ids mapped to this physical channel. This list is sorted into
      * ascending numerical order. Each id in this list must match the id in
      * {@link com.android.internal.telephony.dataconnection.DataConnection}. An empty list means the
      * physical channel has no data call mapped to it.
      *
-     * @return an integer list indicates the data call ids.
+     * @return an integer list indicates the data call ids,
      * @hide
      */
     public int[] getContextIds() {
@@ -135,7 +183,18 @@
     }
 
     /**
-     * @return the rough frequency range for this physical channel.
+     * @return the absolute radio frequency channel number for this physical channel,
+     * {@link #CHANNEL_NUMBER_UNKNOWN} if unknown.
+     * @deprecated Use {@link #getDownlinkChannelNumber()} to get the channel number.
+     */
+    @Deprecated
+    public int getChannelNumber() {
+        return getDownlinkChannelNumber();
+    }
+
+    /**
+     * @return the rough frequency range for this physical channel,
+     * {@link ServiceState#FREQUENCY_RANGE_UNKNOWN} if unknown.
      * @see {@link ServiceState#FREQUENCY_RANGE_LOW}
      * @see {@link ServiceState#FREQUENCY_RANGE_MID}
      * @see {@link ServiceState#FREQUENCY_RANGE_HIGH}
@@ -148,11 +207,48 @@
     }
 
     /**
-     * @return the absolute radio frequency channel number for this physical channel,
+     * @return Downlink Absolute Radio Frequency Channel Number,
      * {@link #CHANNEL_NUMBER_UNKNOWN} if unknown.
      */
-    public int getChannelNumber() {
-        return mChannelNumber;
+    @IntRange(from = 0)
+    public int getDownlinkChannelNumber() {
+        return mDownlinkChannelNumber;
+    }
+
+    /**
+     * @return Uplink Absolute Radio Frequency Channel Number,
+     * {@link #CHANNEL_NUMBER_UNKNOWN} if unknown.
+     */
+    @IntRange(from = 0)
+    public int getUplinkChannelNumber() {
+        return mUplinkChannelNumber;
+    }
+
+    /**
+     * The valid bands are {@link AccessNetworkConstants.GeranBand},
+     * {@link AccessNetworkConstants.UtranBand}, {@link AccessNetworkConstants.EutranBand} and
+     * {@link AccessNetworkConstants.NgranBands}.
+     *
+     * @return the frequency band, {@link #BAND_UNKNOWN} if unknown. */
+    @IntRange(from = 1, to = 261)
+    public int getBand() {
+        return mBand;
+    }
+
+    /**
+     * @return The downlink frequency in kHz, {@link #FREQUENCY_UNKNOWN} if unknown.
+     */
+    @IntRange(from = 0)
+    public int getDownlinkFrequencyKhz() {
+        return mDownlinkFrequency;
+    }
+
+    /**
+     * @return The uplink frequency in kHz, {@link #FREQUENCY_UNKNOWN} if unknown.
+     */
+    @IntRange(from = 0)
+    public int getUplinkFrequencyKhz() {
+        return mUplinkFrequency;
     }
 
     /**
@@ -173,10 +269,13 @@
         return mPhysicalCellId;
     }
 
-    /**The radio technology for this physical channel. */
+    /**
+     * @return The network type for this physical channel,
+     * {@link TelephonyManager#NETWORK_TYPE_UNKNOWN} if unknown.
+     */
     @NetworkType
     public int getNetworkType() {
-        return mRat;
+        return mNetworkType;
     }
 
     /**
@@ -186,7 +285,7 @@
      * @see #CONNECTION_SECONDARY_SERVING
      * @see #CONNECTION_UNKNOWN
      *
-     * @return Connection status of the cell
+     * @return Connection status of the cell, {@link #CONNECTION_UNKNOWN} if unknown.
      */
     @ConnectionStatus
     public int getConnectionStatus() {
@@ -210,6 +309,97 @@
         }
     }
 
+    private void setDownlinkFrequency() {
+        switch (mNetworkType) {
+            case TelephonyManager.NETWORK_TYPE_NR:
+                mDownlinkFrequency = AccessNetworkUtils.getFrequencyFromNrArfcn(
+                        mDownlinkChannelNumber);
+                break;
+            case TelephonyManager.NETWORK_TYPE_LTE:
+                mDownlinkFrequency = AccessNetworkUtils.getFrequencyFromEarfcn(
+                        mBand, mDownlinkChannelNumber, false);
+                break;
+            case TelephonyManager.NETWORK_TYPE_HSPAP:
+            case TelephonyManager.NETWORK_TYPE_TD_SCDMA:
+            case TelephonyManager.NETWORK_TYPE_UMTS:
+            case TelephonyManager.NETWORK_TYPE_HSDPA:
+            case TelephonyManager.NETWORK_TYPE_HSUPA:
+            case TelephonyManager.NETWORK_TYPE_HSPA:
+                mDownlinkFrequency = AccessNetworkUtils.getFrequencyFromUarfcn(
+                        mBand, mDownlinkChannelNumber, false);
+                break;
+            case TelephonyManager.NETWORK_TYPE_GPRS:
+            case TelephonyManager.NETWORK_TYPE_EDGE:
+            case TelephonyManager.NETWORK_TYPE_GSM:
+                mDownlinkFrequency = AccessNetworkUtils.getFrequencyFromArfcn(
+                        mBand, mDownlinkChannelNumber, false);
+                break;
+        }
+    }
+
+    private void setUplinkFrequency() {
+        switch (mNetworkType){
+            case TelephonyManager.NETWORK_TYPE_NR:
+                mUplinkFrequency = mDownlinkFrequency;
+                break;
+            case TelephonyManager.NETWORK_TYPE_LTE:
+                mUplinkFrequency = AccessNetworkUtils.getFrequencyFromEarfcn(
+                        mBand, mUplinkChannelNumber, true);
+                break;
+            case TelephonyManager.NETWORK_TYPE_HSPAP:
+            case TelephonyManager.NETWORK_TYPE_TD_SCDMA:
+            case TelephonyManager.NETWORK_TYPE_UMTS:
+            case TelephonyManager.NETWORK_TYPE_HSDPA:
+            case TelephonyManager.NETWORK_TYPE_HSUPA:
+            case TelephonyManager.NETWORK_TYPE_HSPA:
+                mUplinkFrequency = AccessNetworkUtils.getFrequencyFromUarfcn(
+                        mBand, mUplinkChannelNumber, true);
+                break;
+            case TelephonyManager.NETWORK_TYPE_GPRS:
+            case TelephonyManager.NETWORK_TYPE_EDGE:
+            case TelephonyManager.NETWORK_TYPE_GSM:
+                mUplinkFrequency = AccessNetworkUtils.getFrequencyFromArfcn(
+                        mBand, mUplinkChannelNumber, true);
+                break;
+        }
+    }
+
+    private void setFrequencyRange() {
+        if (mFrequencyRange != ServiceState.FREQUENCY_RANGE_UNKNOWN) {
+            return;
+        }
+
+        switch (mNetworkType) {
+            case TelephonyManager.NETWORK_TYPE_NR:
+                mFrequencyRange = AccessNetworkUtils.getFrequencyRangeGroupFromNrBand(mBand);
+                break;
+            case TelephonyManager.NETWORK_TYPE_LTE:
+                mFrequencyRange = AccessNetworkUtils.getFrequencyRangeGroupFromEutranBand(mBand);
+                break;
+            case TelephonyManager.NETWORK_TYPE_HSPAP:
+            case TelephonyManager.NETWORK_TYPE_TD_SCDMA:
+            case TelephonyManager.NETWORK_TYPE_UMTS:
+            case TelephonyManager.NETWORK_TYPE_HSDPA:
+            case TelephonyManager.NETWORK_TYPE_HSUPA:
+            case TelephonyManager.NETWORK_TYPE_HSPA:
+                mFrequencyRange = AccessNetworkUtils.getFrequencyRangeGroupFromUtranBand(mBand);
+                break;
+            case TelephonyManager.NETWORK_TYPE_GPRS:
+            case TelephonyManager.NETWORK_TYPE_EDGE:
+            case TelephonyManager.NETWORK_TYPE_GSM:
+                mFrequencyRange = AccessNetworkUtils.getFrequencyRangeGroupFromGeranBand(mBand);
+                break;
+            default:
+                mFrequencyRange = ServiceState.FREQUENCY_RANGE_UNKNOWN;
+                break;
+        }
+
+        if (mFrequencyRange == ServiceState.FREQUENCY_RANGE_UNKNOWN) {
+            mFrequencyRange = AccessNetworkUtils.getFrequencyRangeFromArfcn(
+                    mDownlinkFrequency);
+        }
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) {
@@ -223,30 +413,37 @@
         PhysicalChannelConfig config = (PhysicalChannelConfig) o;
         return mCellConnectionStatus == config.mCellConnectionStatus
                 && mCellBandwidthDownlinkKhz == config.mCellBandwidthDownlinkKhz
-                && mRat == config.mRat
+                && mCellBandwidthUplinkKhz == config.mCellBandwidthUplinkKhz
+                && mNetworkType == config.mNetworkType
                 && mFrequencyRange == config.mFrequencyRange
-                && mChannelNumber == config.mChannelNumber
+                && mDownlinkChannelNumber == config.mDownlinkChannelNumber
+                && mUplinkChannelNumber == config.mUplinkChannelNumber
                 && mPhysicalCellId == config.mPhysicalCellId
-                && Arrays.equals(mContextIds, config.mContextIds);
+                && Arrays.equals(mContextIds, config.mContextIds)
+                && mBand == config.mBand
+                && mDownlinkFrequency == config.mDownlinkFrequency
+                && mUplinkFrequency == config.mUplinkFrequency;
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(
-                mCellConnectionStatus, mCellBandwidthDownlinkKhz, mRat, mFrequencyRange,
-                mChannelNumber, mPhysicalCellId, mContextIds);
+                mCellConnectionStatus, mCellBandwidthDownlinkKhz, mCellBandwidthUplinkKhz,
+                mNetworkType, mFrequencyRange, mDownlinkChannelNumber, mUplinkChannelNumber,
+                mContextIds, mPhysicalCellId, mBand, mDownlinkFrequency, mUplinkFrequency);
     }
 
-    public static final @android.annotation.NonNull Parcelable.Creator<PhysicalChannelConfig> CREATOR =
-        new Parcelable.Creator<PhysicalChannelConfig>() {
-            public PhysicalChannelConfig createFromParcel(Parcel in) {
-                return new PhysicalChannelConfig(in);
-            }
+    public static final
+    @android.annotation.NonNull Parcelable.Creator<PhysicalChannelConfig> CREATOR =
+            new Parcelable.Creator<PhysicalChannelConfig>() {
+                public PhysicalChannelConfig createFromParcel(Parcel in) {
+                    return new PhysicalChannelConfig(in);
+                }
 
-            public PhysicalChannelConfig[] newArray(int size) {
-                return new PhysicalChannelConfig[size];
-            }
-        };
+                public PhysicalChannelConfig[] newArray(int size) {
+                    return new PhysicalChannelConfig[size];
+                }
+            };
 
     @Override
     public String toString() {
@@ -255,44 +452,64 @@
                 .append(getConnectionStatusString())
                 .append(",mCellBandwidthDownlinkKhz=")
                 .append(mCellBandwidthDownlinkKhz)
-                .append(",mRat=")
-                .append(TelephonyManager.getNetworkTypeName(mRat))
+                .append(",mCellBandwidthUplinkKhz=")
+                .append(mCellBandwidthUplinkKhz)
+                .append(",mNetworkType=")
+                .append(TelephonyManager.getNetworkTypeName(mNetworkType))
                 .append(",mFrequencyRange=")
                 .append(ServiceState.frequencyRangeToString(mFrequencyRange))
-                .append(",mChannelNumber=")
-                .append(mChannelNumber)
+                .append(",mDownlinkChannelNumber=")
+                .append(mDownlinkChannelNumber)
+                .append(",mUplinkChannelNumber=")
+                .append(mUplinkChannelNumber)
                 .append(",mContextIds=")
                 .append(Arrays.toString(mContextIds))
                 .append(",mPhysicalCellId=")
                 .append(mPhysicalCellId)
+                .append(",mBand=")
+                .append(mBand)
+                .append(",mDownlinkFrequency=")
+                .append(mDownlinkFrequency)
+                .append(",mUplinkFrequency=")
+                .append(mUplinkFrequency)
                 .append("}")
                 .toString();
     }
 
-    /** @hide */
-    public PhysicalChannelConfig(int status, int bandwidth) {
-        mCellConnectionStatus = status;
-        mCellBandwidthDownlinkKhz = bandwidth;
-    }
-
     private PhysicalChannelConfig(Parcel in) {
         mCellConnectionStatus = in.readInt();
         mCellBandwidthDownlinkKhz = in.readInt();
-        mRat = in.readInt();
-        mChannelNumber = in.readInt();
+        mCellBandwidthUplinkKhz = in.readInt();
+        mNetworkType = in.readInt();
+        mDownlinkChannelNumber = in.readInt();
+        mUplinkChannelNumber = in.readInt();
         mFrequencyRange = in.readInt();
         mContextIds = in.createIntArray();
         mPhysicalCellId = in.readInt();
+        mBand = in.readInt();
+        if (mBand > BAND_UNKNOWN) {
+            setDownlinkFrequency();
+            setUplinkFrequency();
+            setFrequencyRange();
+        }
     }
 
     private PhysicalChannelConfig(Builder builder) {
         mCellConnectionStatus = builder.mCellConnectionStatus;
         mCellBandwidthDownlinkKhz = builder.mCellBandwidthDownlinkKhz;
-        mRat = builder.mRat;
-        mChannelNumber = builder.mChannelNumber;
+        mCellBandwidthUplinkKhz = builder.mCellBandwidthUplinkKhz;
+        mNetworkType = builder.mNetworkType;
+        mDownlinkChannelNumber = builder.mDownlinkChannelNumber;
+        mUplinkChannelNumber = builder.mUplinkChannelNumber;
         mFrequencyRange = builder.mFrequencyRange;
         mContextIds = builder.mContextIds;
         mPhysicalCellId = builder.mPhysicalCellId;
+        mBand = builder.mBand;
+        if (mBand > BAND_UNKNOWN) {
+            setDownlinkFrequency();
+            setUplinkFrequency();
+            setFrequencyRange();
+        }
     }
 
     /**
@@ -300,61 +517,105 @@
      * @hide
      */
     public static final class Builder {
-        private int mRat;
+        private int mNetworkType;
         private int mFrequencyRange;
-        private int mChannelNumber;
+        private int mDownlinkChannelNumber;
+        private int mUplinkChannelNumber;
         private int mCellBandwidthDownlinkKhz;
+        private int mCellBandwidthUplinkKhz;
         private int mCellConnectionStatus;
         private int[] mContextIds;
         private int mPhysicalCellId;
+        private int mBand;
 
         public Builder() {
-            mRat = ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN;
+            mNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
             mFrequencyRange = ServiceState.FREQUENCY_RANGE_UNKNOWN;
-            mChannelNumber = CHANNEL_NUMBER_UNKNOWN;
-            mCellBandwidthDownlinkKhz = 0;
+            mDownlinkChannelNumber = CHANNEL_NUMBER_UNKNOWN;
+            mUplinkChannelNumber = CHANNEL_NUMBER_UNKNOWN;
+            mCellBandwidthDownlinkKhz = CELL_BANDWIDTH_UNKNOWN;
+            mCellBandwidthUplinkKhz = CELL_BANDWIDTH_UNKNOWN;
             mCellConnectionStatus = CONNECTION_UNKNOWN;
             mContextIds = new int[0];
             mPhysicalCellId = PHYSICAL_CELL_ID_UNKNOWN;
+            mBand = BAND_UNKNOWN;
         }
 
         public PhysicalChannelConfig build() {
             return new PhysicalChannelConfig(this);
         }
 
-        public Builder setRat(int rat) {
-            this.mRat = rat;
+        public @NonNull Builder setNetworkType(@NetworkType int networkType) {
+            if (!TelephonyManager.isNetworkTypeValid(networkType)) {
+                throw new IllegalArgumentException("Network type: " + networkType + " is invalid.");
+            }
+            mNetworkType = networkType;
             return this;
         }
 
-        public Builder setFrequencyRange(int frequencyRange) {
-            this.mFrequencyRange = frequencyRange;
+        public @NonNull Builder setFrequencyRange(int frequencyRange) {
+            if (!ServiceState.isFrequencyRangeValid(frequencyRange)) {
+                throw new IllegalArgumentException("Frequency range: " + frequencyRange +
+                        " is invalid.");
+            }
+            mFrequencyRange = frequencyRange;
             return this;
         }
 
-        public Builder setChannelNumber(int channelNumber) {
-            this.mChannelNumber = channelNumber;
+        public @NonNull Builder setDownlinkChannelNumber(int downlinkChannelNumber) {
+            mDownlinkChannelNumber = downlinkChannelNumber;
             return this;
         }
 
-        public Builder setCellBandwidthDownlinkKhz(int cellBandwidthDownlinkKhz) {
-            this.mCellBandwidthDownlinkKhz = cellBandwidthDownlinkKhz;
+        public @NonNull Builder setUplinkChannelNumber(int uplinkChannelNumber) {
+            mUplinkChannelNumber = uplinkChannelNumber;
             return this;
         }
 
-        public Builder setCellConnectionStatus(int connectionStatus) {
-            this.mCellConnectionStatus = connectionStatus;
+        public @NonNull Builder setCellBandwidthDownlinkKhz(int cellBandwidthDownlinkKhz) {
+            if (cellBandwidthDownlinkKhz < CELL_BANDWIDTH_UNKNOWN) {
+                throw new IllegalArgumentException("Cell downlink bandwidth(kHz): " +
+                        cellBandwidthDownlinkKhz + " is invalid.");
+            }
+            mCellBandwidthDownlinkKhz = cellBandwidthDownlinkKhz;
             return this;
         }
 
-        public Builder setContextIds(int[] contextIds) {
+        public @NonNull Builder setCellBandwidthUplinkKhz(int cellBandwidthUplinkKhz) {
+            if (cellBandwidthUplinkKhz < CELL_BANDWIDTH_UNKNOWN) {
+                throw new IllegalArgumentException("Cell uplink bandwidth(kHz): "+
+                        cellBandwidthUplinkKhz +" is invalid.");
+            }
+            mCellBandwidthUplinkKhz = cellBandwidthUplinkKhz;
+            return this;
+        }
+
+        public @NonNull Builder setCellConnectionStatus(int connectionStatus) {
+            mCellConnectionStatus = connectionStatus;
+            return this;
+        }
+
+        public @NonNull Builder setContextIds(int[] contextIds) {
             if (contextIds != null) Arrays.sort(contextIds);
-            this.mContextIds = contextIds;
+            mContextIds = contextIds;
             return this;
         }
 
-        public Builder setPhysicalCellId(int physicalCellId) {
-            this.mPhysicalCellId = physicalCellId;
+        public @NonNull Builder setPhysicalCellId(int physicalCellId) {
+            if (physicalCellId > PHYSICAL_CELL_ID_MAXIMUM_VALUE) {
+                throw new IllegalArgumentException("Physical cell Id: " + physicalCellId +
+                        " is over limit.");
+            }
+            mPhysicalCellId = physicalCellId;
+            return this;
+        }
+
+        public @NonNull Builder setBand(int band) {
+            if (band <= BAND_UNKNOWN) {
+                throw new IllegalArgumentException("Band: " + band +
+                        " is invalid.");
+            }
+            mBand = band;
             return this;
         }
     }
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index dedb1af..f110dae 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -2111,4 +2111,23 @@
         }
         return false;
     }
+
+    /**
+     * The frequency range is valid or not.
+     *
+     * @param frequencyRange The frequency range {@link FrequencyRange}.
+     * @return {@code true} if valid, {@code false} otherwise.
+     *
+     * @hide
+     */
+    public static boolean isFrequencyRangeValid(int frequencyRange) {
+        if (frequencyRange == FREQUENCY_RANGE_LOW
+                || frequencyRange == FREQUENCY_RANGE_MID
+                || frequencyRange == FREQUENCY_RANGE_HIGH
+                || frequencyRange == FREQUENCY_RANGE_MMWAVE) {
+            return true;
+        } else {
+            return false;
+        }
+    }
 }
diff --git a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
new file mode 100644
index 0000000..2a16402
--- /dev/null
+++ b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
@@ -0,0 +1,251 @@
+/*
+ * 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.telephony;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Request used to register {@link SignalThresholdInfo} to be notified when the signal strength
+ * breach the specified thresholds.
+ */
+public final class SignalStrengthUpdateRequest implements Parcelable {
+    /**
+     * List of SignalThresholdInfo for the request.
+     */
+    private final List<SignalThresholdInfo> mSignalThresholdInfos;
+
+    /**
+     * Whether the reporting is required for thresholds in the request while device is idle.
+     */
+    private final boolean mIsReportingRequestedWhileIdle;
+
+    /**
+     * Whether the reporting requested for system thresholds while device is idle.
+     *
+     * System signal thresholds are loaded from carrier config items and mainly used for UI
+     * displaying. By default, they are ignored when device is idle. When setting the value to true,
+     * modem will continue reporting signal strength changes over the system signal thresholds even
+     * device is idle.
+     *
+     * This should only set to true by the system caller.
+     */
+    private final boolean mIsSystemThresholdReportingRequestedWhileIdle;
+
+    private SignalStrengthUpdateRequest(
+            @NonNull List<SignalThresholdInfo> signalThresholdInfos,
+            boolean isReportingRequestedWhileIdle,
+            boolean isSystemThresholdReportingRequestedWhileIdle) {
+        validate(signalThresholdInfos);
+
+        mSignalThresholdInfos = signalThresholdInfos;
+        mIsReportingRequestedWhileIdle = isReportingRequestedWhileIdle;
+        mIsSystemThresholdReportingRequestedWhileIdle =
+                isSystemThresholdReportingRequestedWhileIdle;
+    }
+
+    /**
+     * Builder class to create {@link SignalStrengthUpdateRequest} object.
+     */
+    public static final class Builder {
+        private List<SignalThresholdInfo> mSignalThresholdInfos = null;
+        private boolean mIsReportingRequestedWhileIdle = false;
+        private boolean mIsSystemThresholdReportingRequestedWhileIdle = false;
+
+        /**
+         * Set the collection of SignalThresholdInfo for the builder object
+         *
+         * @param signalThresholdInfos the collection of SignalThresholdInfo
+         *
+         * @return the builder to facilitate the chaining
+         */
+        public @NonNull Builder setSignalThresholdInfos(
+                @NonNull Collection<SignalThresholdInfo> signalThresholdInfos) {
+            Objects.requireNonNull(signalThresholdInfos,
+                    "SignalThresholdInfo collection must not be null");
+            for (SignalThresholdInfo info : signalThresholdInfos) {
+                Objects.requireNonNull(info,
+                        "SignalThresholdInfo in the collection must not be null");
+            }
+
+            mSignalThresholdInfos = new ArrayList<>(signalThresholdInfos);
+            // Sort the collection with RAN ascending order, make the ordering not matter for equals
+            mSignalThresholdInfos.sort(
+                    Comparator.comparingInt(SignalThresholdInfo::getRadioAccessNetworkType));
+            return this;
+        }
+
+        /**
+         * Set the builder object if require reporting on thresholds in this request when device is
+         * idle.
+         *
+         * @param isReportingRequestedWhileIdle true if request reporting when device is idle
+         *
+         * @return the builder to facilitate the chaining
+         */
+        public @NonNull Builder setReportingRequestedWhileIdle(
+                boolean isReportingRequestedWhileIdle) {
+            mIsReportingRequestedWhileIdle = isReportingRequestedWhileIdle;
+            return this;
+        }
+
+        /**
+         * Set the builder object if require reporting on the system thresholds when device is idle.
+         *
+         * This can only used by the system caller.
+         *
+         * @param isSystemThresholdReportingRequestedWhileIdle true if request reporting on the
+         *                                                     system thresholds when device is idle
+         * @return the builder to facilitate the chaining
+         * @hide
+         */
+        public @NonNull Builder setSystemThresholdReportingRequestedWhileIdle(
+                boolean isSystemThresholdReportingRequestedWhileIdle) {
+            mIsSystemThresholdReportingRequestedWhileIdle =
+                    isSystemThresholdReportingRequestedWhileIdle;
+            return this;
+        }
+
+        /**
+         * Build a {@link SignalStrengthUpdateRequest} object.
+         *
+         * @return the SignalStrengthUpdateRequest object
+         *
+         * @throws IllegalArgumentException if the SignalThresholdInfo collection is empty size, the
+         * radio access network type in the collection is not unique
+         */
+        public @NonNull SignalStrengthUpdateRequest build() {
+            return new SignalStrengthUpdateRequest(mSignalThresholdInfos,
+                    mIsReportingRequestedWhileIdle, mIsSystemThresholdReportingRequestedWhileIdle);
+        }
+    }
+
+    private SignalStrengthUpdateRequest(Parcel in) {
+        mSignalThresholdInfos = in.createTypedArrayList(SignalThresholdInfo.CREATOR);
+        mIsReportingRequestedWhileIdle = in.readBoolean();
+        mIsSystemThresholdReportingRequestedWhileIdle = in.readBoolean();
+    }
+
+    /**
+     * Get the collection of SignalThresholdInfo in the request.
+     *
+     * @return the collection of SignalThresholdInfo
+     */
+    @NonNull
+    public Collection<SignalThresholdInfo> getSignalThresholdInfos() {
+        return Collections.unmodifiableList(mSignalThresholdInfos);
+    }
+
+    /**
+     * Get whether reporting is requested for the threshold in the request while device is idle.
+     *
+     * @return true if reporting requested while device is idle
+     */
+    public boolean isReportingRequestedWhileIdle() {
+        return mIsReportingRequestedWhileIdle;
+    }
+
+    /**
+     * @return true if reporting requested for system thresholds while device is idle
+     *
+     * @hide
+     */
+    public boolean isSystemThresholdReportingRequestedWhileIdle() {
+        return mIsSystemThresholdReportingRequestedWhileIdle;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeTypedList(mSignalThresholdInfos);
+        dest.writeBoolean(mIsReportingRequestedWhileIdle);
+        dest.writeBoolean(mIsSystemThresholdReportingRequestedWhileIdle);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) return true;
+
+        if (!(other instanceof SignalStrengthUpdateRequest)) {
+            return false;
+        }
+
+        SignalStrengthUpdateRequest request = (SignalStrengthUpdateRequest) other;
+        return request.mSignalThresholdInfos.equals(mSignalThresholdInfos)
+                && request.mIsReportingRequestedWhileIdle == mIsReportingRequestedWhileIdle
+                && request.mIsSystemThresholdReportingRequestedWhileIdle
+                == mIsSystemThresholdReportingRequestedWhileIdle;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mSignalThresholdInfos, mIsReportingRequestedWhileIdle,
+                mIsSystemThresholdReportingRequestedWhileIdle);
+    }
+
+    public static final @NonNull Parcelable.Creator<SignalStrengthUpdateRequest> CREATOR =
+            new Parcelable.Creator<SignalStrengthUpdateRequest>() {
+                @Override
+                public SignalStrengthUpdateRequest createFromParcel(Parcel source) {
+                    return new SignalStrengthUpdateRequest(source);
+                }
+
+                @Override
+                public SignalStrengthUpdateRequest[] newArray(int size) {
+                    return new SignalStrengthUpdateRequest[size];
+                }
+            };
+
+    @Override
+    public String toString() {
+        return new StringBuilder("SignalStrengthUpdateRequest{")
+                .append("mSignalThresholdInfos=")
+                .append(mSignalThresholdInfos)
+                .append(" mIsReportingRequestedWhileIdle=")
+                .append(mIsReportingRequestedWhileIdle)
+                .append(" mIsSystemThresholdReportingRequestedWhileIdle=")
+                .append(mIsSystemThresholdReportingRequestedWhileIdle)
+                .append("}").toString();
+    }
+
+    /**
+     * Throw IAE when the RAN in the collection is not unique.
+     */
+    private static void validate(Collection<SignalThresholdInfo> infos) {
+        Set<Integer> uniqueRan = new HashSet<>(infos.size());
+        for (SignalThresholdInfo info : infos) {
+            final int ran = info.getRadioAccessNetworkType();
+            if (!uniqueRan.add(ran)) {
+                throw new IllegalArgumentException("RAN: " + ran + " is not unique");
+            }
+        }
+    }
+}
diff --git a/telephony/java/android/telephony/SignalThresholdInfo.java b/telephony/java/android/telephony/SignalThresholdInfo.java
index 8a472ad..0059ad6 100644
--- a/telephony/java/android/telephony/SignalThresholdInfo.java
+++ b/telephony/java/android/telephony/SignalThresholdInfo.java
@@ -28,13 +28,11 @@
 
 /**
  * Defines the threshold value of the signal strength.
- * @hide
  */
 public final class SignalThresholdInfo implements Parcelable {
 
     /**
      * Unknown signal measurement type.
-     * @hide
      */
     public static final int SIGNAL_MEASUREMENT_TYPE_UNKNOWN = 0;
 
@@ -44,7 +42,6 @@
      * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#GERAN},
      *           {@link AccessNetworkConstants.AccessNetworkType#CDMA2000}
      * Reference: 3GPP TS 27.007 section 8.5.
-     * @hide
      */
     public static final int SIGNAL_MEASUREMENT_TYPE_RSSI = 1;
 
@@ -53,7 +50,6 @@
      * Range: -120 dBm to -25 dBm;
      * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#UTRAN}
      * Reference: 3GPP TS 25.123, section 9.1.1.1
-     * @hide
      */
     public static final int SIGNAL_MEASUREMENT_TYPE_RSCP = 2;
 
@@ -62,7 +58,6 @@
      * Range: -140 dBm to -44 dBm;
      * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#EUTRAN}
      * Reference: 3GPP TS 36.133 9.1.4
-     * @hide
      */
     public static final int SIGNAL_MEASUREMENT_TYPE_RSRP = 3;
 
@@ -71,7 +66,6 @@
      * Range: -34 dB to 3 dB;
      * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#EUTRAN}
      * Reference: 3GPP TS 36.133 9.1.7
-     * @hide
      */
     public static final int SIGNAL_MEASUREMENT_TYPE_RSRQ = 4;
 
@@ -79,7 +73,6 @@
      * Reference Signal Signal to Noise Ratio
      * Range: -20 dB to 30 dB;
      * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#EUTRAN}
-     * @hide
      */
     public static final int SIGNAL_MEASUREMENT_TYPE_RSSNR = 5;
 
@@ -88,7 +81,6 @@
      * Range: -140 dBm to -44 dBm.
      * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#NGRAN}
      * Reference: 3GPP TS 38.215.
-     * @hide
      */
     public static final int SIGNAL_MEASUREMENT_TYPE_SSRSRP = 6;
 
@@ -97,7 +89,6 @@
      * Range: -43 dB to 20 dB.
      * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#NGRAN}
      * Reference: 3GPP TS 38.133 section 10.1.11.1.
-     * @hide
      */
     public static final int SIGNAL_MEASUREMENT_TYPE_SSRSRQ = 7;
 
@@ -106,7 +97,6 @@
      * Range: -23 dB to 40 dB
      * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#NGRAN}
      * Reference: 3GPP TS 38.215 section 5.1.*, 3GPP TS 38.133 section 10.1.16.1.
-     * @hide
      */
     public static final int SIGNAL_MEASUREMENT_TYPE_SSSINR = 8;
 
@@ -290,6 +280,20 @@
     public static final int SIGNAL_SSSINR_MAX_VALUE = 40;
 
     /**
+     * The minimum number of thresholds allowed in each SignalThresholdInfo.
+     *
+     * @hide
+     */
+    public static final int MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED = 1;
+
+    /**
+     * The maximum number of thresholds allowed in each SignalThresholdInfo.
+     *
+     * @hide
+     */
+    public static final int MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED = 4;
+
+    /**
      * Constructor
      *
      * @param ran               Radio Access Network type
@@ -316,8 +320,6 @@
 
     /**
      * Builder class to create {@link SignalThresholdInfo} objects.
-     *
-     * @hide
      */
     public static final class Builder {
         private int mRan = AccessNetworkConstants.AccessNetworkType.UNKNOWN;
@@ -378,20 +380,57 @@
         }
 
         /**
-         * Set the signal threshold values of the corresponding signal measurement type.
+         * Set the signal strength thresholds of the corresponding signal measurement type.
          *
-         * The range and unit must reference specific SignalMeasurementType.
+         * The range and unit must reference specific SignalMeasurementType. The length of the
+         * thresholds should between the numbers return from
+         * {@link #getMinimumNumberOfThresholdsAllowed()} and
+         * {@link #getMaximumNumberOfThresholdsAllowed()}. An IllegalArgumentException will throw
+         * otherwise.
          *
          * @param thresholds array of integer as the signal threshold values
          * @return the builder to facilitate the chaining
+         *
+         * @see #SIGNAL_MEASUREMENT_TYPE_RSSI
+         * @see #SIGNAL_MEASUREMENT_TYPE_RSCP
+         * @see #SIGNAL_MEASUREMENT_TYPE_RSRP
+         * @see #SIGNAL_MEASUREMENT_TYPE_RSRQ
+         * @see #SIGNAL_MEASUREMENT_TYPE_RSSNR
+         * @see #SIGNAL_MEASUREMENT_TYPE_SSRSRP
+         * @see #SIGNAL_MEASUREMENT_TYPE_SSRSRQ
+         * @see #SIGNAL_MEASUREMENT_TYPE_SSSINR
+         * @see #getThresholds() for more details on signal strength thresholds
          */
         public @NonNull Builder setThresholds(@NonNull int[] thresholds) {
             Objects.requireNonNull(thresholds, "thresholds must not be null");
+            if (thresholds.length < MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED
+                    || thresholds.length > MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED) {
+                throw new IllegalArgumentException(
+                        "thresholds length must between " + MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED
+                                + " and " + MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED);
+            }
+            mThresholds = thresholds.clone();
+            Arrays.sort(mThresholds);
+            return this;
+        }
+
+        /**
+         * Set the signal strength thresholds for the corresponding signal measurement type without
+         * the length limitation.
+         *
+         * @param thresholds array of integer as the signal threshold values
+         * @return the builder to facilitate the chaining
+         *
+         * @hide
+         */
+        public @NonNull Builder setThresholdsUnlimited(@NonNull int[] thresholds) {
+            Objects.requireNonNull(thresholds, "thresholds must not be null");
             mThresholds = thresholds.clone();
             Arrays.sort(mThresholds);
             return this;
         }
 
+
         /**
          * Set if the modem should trigger the report based on the criteria.
          *
@@ -423,8 +462,6 @@
      * Get the radio access network type.
      *
      * @return radio access network type
-     *
-     * @hide
      */
     public @AccessNetworkConstants.RadioAccessNetworkType int getRadioAccessNetworkType() {
         return mRan;
@@ -434,8 +471,6 @@
      * Get the signal measurement type.
      *
      * @return the SignalMeasurementType value
-     *
-     * @hide
      */
     public @SignalMeasurementType int getSignalMeasurementType() {
         return mSignalMeasurementType;
@@ -457,16 +492,47 @@
     }
 
     /**
-     * Get the signal threshold values.
+     * Get the signal strength thresholds.
+     *
+     * Signal strength thresholds are a list of integer used for suggesting signal level and signal
+     * reporting criteria. The range and unit must reference specific SignalMeasurementType.
+     *
+     * Please refer to https://source.android.com/devices/tech/connect/signal-strength on how signal
+     * strength thresholds are used for signal strength reporting.
      *
      * @return array of integer of the signal thresholds
      *
-     * @hide
+     * @see #SIGNAL_MEASUREMENT_TYPE_RSSI
+     * @see #SIGNAL_MEASUREMENT_TYPE_RSCP
+     * @see #SIGNAL_MEASUREMENT_TYPE_RSRP
+     * @see #SIGNAL_MEASUREMENT_TYPE_RSRQ
+     * @see #SIGNAL_MEASUREMENT_TYPE_RSSNR
+     * @see #SIGNAL_MEASUREMENT_TYPE_SSRSRP
+     * @see #SIGNAL_MEASUREMENT_TYPE_SSRSRQ
+     * @see #SIGNAL_MEASUREMENT_TYPE_SSSINR
      */
     public @NonNull int[] getThresholds() {
         return mThresholds.clone();
     }
 
+    /**
+     * Get the minimum number of thresholds allowed in each SignalThresholdInfo.
+     *
+     * @return the minimum number of thresholds allowed
+     */
+    public static int getMinimumNumberOfThresholdsAllowed() {
+        return MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED;
+    }
+
+    /**
+     * Get the maximum number of threshold allowed in each SignalThresholdInfo.
+     *
+     * @return the maximum number of thresholds allowed
+     */
+    public static int getMaximumNumberOfThresholdsAllowed() {
+        return MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED;
+    }
+
     @Override
     public int describeContents() {
         return 0;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 2190eb1..2f577a9 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -131,10 +131,12 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
@@ -15185,4 +15187,17 @@
             e.execute(() -> callback.onAuthenticationFailure(GBA_FAILURE_REASON_FEATURE_NOT_READY));
         }
     }
+
+    /**
+     * The network type is valid or not.
+     *
+     * @param networkType The network type {@link NetworkType}.
+     * @return {@code true} if valid, {@code false} otherwise.
+     *
+     * @hide
+     */
+    public static boolean isNetworkTypeValid(@NetworkType int networkType) {
+        return networkType >= TelephonyManager.NETWORK_TYPE_UNKNOWN &&
+                networkType <= TelephonyManager.NETWORK_TYPE_NR;
+    }
 }
diff --git a/telephony/java/android/telephony/euicc/DownloadableSubscription.java b/telephony/java/android/telephony/euicc/DownloadableSubscription.java
index 3412079..a5150b0 100644
--- a/telephony/java/android/telephony/euicc/DownloadableSubscription.java
+++ b/telephony/java/android/telephony/euicc/DownloadableSubscription.java
@@ -121,25 +121,21 @@
         }
 
         public Builder(@NonNull String encodedActivationCode) {
-            Preconditions.checkNotNull(encodedActivationCode, "Activation code may not be null");
             this.encodedActivationCode = encodedActivationCode;
         }
 
         /**
-         * Builds a {@link DownloadableSubscription} object. If the encoded activation code is
-         * {@code null}, a {@link NullPointerException} will be thrown.
+         * Builds a {@link DownloadableSubscription} object.
          * @return a non-null {@link DownloadableSubscription} object.
          */
         @NonNull
         public DownloadableSubscription build() {
-            Preconditions.checkNotNull(encodedActivationCode, "Activation code may not be null");
             return new DownloadableSubscription(encodedActivationCode, confirmationCode,
                     carrierName, accessRules);
         }
 
         /**
-         * Sets the encoded activation code. If the encoded activation code is {@code null}, a
-         * {@link NullPointerException} will be thrown.
+         * Sets the encoded activation code.
          * @param value the activation code to use. An activation code can be parsed from a user
          *              scanned QR code. The format of activation code is defined in SGP.22. For
          *              example, "1$SMDP.GSMA.COM$04386-AGYFT-A74Y8-3F815$1.3.6.1.4.1.31746". For
@@ -147,7 +143,6 @@
          */
         @NonNull
         public Builder setEncodedActivationCode(@NonNull String value) {
-            Preconditions.checkNotNull(encodedActivationCode, "Activation code may not be null");
             encodedActivationCode = value;
             return this;
         }
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 9a2def9..1a940c7 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -1016,6 +1016,15 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="RippleActivity"
+                  android:label="Animation/Ripple Animation"
+                  android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="com.android.test.hwui.TEST"/>
+            </intent-filter>
+        </activity>
+
         <activity android:name="MultiProducerActivity"
              android:label="Threads/Multiple Producers"
              android:exported="true">
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
index b53b78a..8be3b7e 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
@@ -35,9 +35,6 @@
 import android.os.Bundle;
 import android.view.View;
 
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
 @SuppressWarnings({"UnusedDeclaration"})
 public class ColorFiltersMutateActivity extends Activity {
     @Override
@@ -54,11 +51,13 @@
         private final Paint mLightingPaint;
         private final Paint mBlendPaint;
         private final Paint mShaderPaint;
+        private final RuntimeShader mRuntimeShader;
 
         private float mSaturation = 0.0f;
         private int mLightAdd = 0;
         private int mLightMul = 0;
         private int mPorterDuffColor = 0;
+        private float mShaderParam1 = 0.0f;
 
         static final String sSkSL =
                 "in shader bitmapShader;\n"
@@ -67,8 +66,6 @@
                 + "  return half4(sample(bitmapShader, xy).rgb, param1);\n"
                 + "}\n";
 
-        private byte[] mUniforms = new byte[4];
-
         BitmapsView(Context c) {
             super(c);
 
@@ -86,11 +83,13 @@
             mBlendPaint = new Paint();
             mBlendPaint.setColorFilter(new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_OVER));
 
+            mRuntimeShader = new RuntimeShader(sSkSL, false);
+            mRuntimeShader.setUniform("param1", mShaderParam1);
+            mRuntimeShader.setInputShader("bitmapShader", new BitmapShader(mBitmap1,
+                                                                           Shader.TileMode.CLAMP,
+                                                                           Shader.TileMode.CLAMP));
             mShaderPaint = new Paint();
-            Shader[] inputShaders = { new BitmapShader(mBitmap1, Shader.TileMode.CLAMP,
-                                                       Shader.TileMode.CLAMP) };
-            mShaderPaint.setShader(new RuntimeShader(sSkSL, mUniforms, inputShaders, true));
-            setShaderParam1(0.0f);
+            mShaderPaint.setShader(mRuntimeShader);
 
             ObjectAnimator sat = ObjectAnimator.ofFloat(this, "saturation", 1.0f);
             sat.setDuration(1000);
@@ -177,20 +176,15 @@
         }
 
         public void setShaderParam1(float value) {
-            RuntimeShader shader = (RuntimeShader) mShaderPaint.getShader();
-            ByteBuffer buffer = ByteBuffer.wrap(mUniforms);
-            buffer.order(ByteOrder.LITTLE_ENDIAN);
-            buffer.putFloat(value);
-            shader.updateUniforms(mUniforms);
+            mShaderParam1 = value;
+            mRuntimeShader.setUniform("param1", mShaderParam1);
             invalidate();
         }
 
         // If either valueFrom or valueTo is null, then a getter function will also be derived
         // and called by the animator class.
         public float getShaderParam1() {
-            ByteBuffer buffer = ByteBuffer.wrap(mUniforms);
-            buffer.order(ByteOrder.LITTLE_ENDIAN);
-            return buffer.getFloat();
+            return mShaderParam1;
         }
 
         @Override
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java
new file mode 100644
index 0000000..f6d9a73
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.CanvasProperty;
+import android.graphics.Paint;
+import android.graphics.RecordingCanvas;
+import android.graphics.RuntimeShader;
+import android.os.Bundle;
+import android.os.Trace;
+import android.view.RenderNodeAnimator;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.LinearLayout.LayoutParams;
+
+import java.util.ArrayList;
+
+public class RippleActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        final LinearLayout layout = new LinearLayout(this);
+        layout.setOrientation(LinearLayout.VERTICAL);
+        layout.addView(new RippleView(this),
+                new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+
+        setContentView(layout);
+    }
+
+    static class RippleView extends View {
+        static final int DURATION = 1000;
+        static final int MAX_RADIUS = 250;
+
+        private boolean mToggle = false;
+        ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<RenderNodeAnimator>();
+
+        CanvasProperty<Float> mX;
+        CanvasProperty<Float> mY;
+        CanvasProperty<Float> mRadius;
+        CanvasProperty<Float> mProgress;
+        CanvasProperty<Paint> mPaint;
+        RuntimeShader mRuntimeShader;
+
+        static final String sSkSL = ""
+                + "uniform float2 in_origin;"
+                + "uniform float in_progress;\n"
+                + "uniform float in_maxRadius;\n"
+                + "uniform shader in_paintColor;\n"
+                + "float dist2(float2 p0, float2 pf) { return sqrt((pf.x - p0.x) * (pf.x - p0.x) + "
+                + "(pf.y - p0.y) * (pf.y - p0.y)); }\n"
+                + "float mod2(float a, float b) { return a - (b * floor(a / b)); }\n"
+                + "float rand(float2 src) { return fract(sin(dot(src.xy, float2(12.9898, 78.233)))"
+                + " * 43758.5453123); }\n"
+                + "float4 main(float2 p)\n"
+                + "{\n"
+                + "    float fraction = in_progress;\n"
+                + "    float2 fragCoord = p;//sk_FragCoord.xy;\n"
+                + "    float maxDist = in_maxRadius;\n"
+                + "    float fragDist = dist2(in_origin, fragCoord.xy);\n"
+                + "    float circleRadius = maxDist * fraction;\n"
+                + "    float colorVal = (fragDist - circleRadius) / maxDist;\n"
+                + "    float d = fragDist < circleRadius \n"
+                + "        ? 1. - abs(colorVal * 2. * smoothstep(0., 1., fraction)) \n"
+                + "        : 1. - abs(colorVal * 3.);\n"
+                + "    d = smoothstep(0., 1., d);\n"
+                + "    float divider = 2.;\n"
+                + "    float x = floor(fragCoord.x / divider);\n"
+                + "    float y = floor(fragCoord.y / divider);\n"
+                + "    float density = .95;\n"
+                + "    d = rand(float2(x, y)) > density ? d : d * .2;\n"
+                + "    d = d * rand(float2(fraction, x * y));\n"
+                + "    float alpha = 1. - pow(fraction, 3.);\n"
+                + "    return float4(sample(in_paintColor).rgb, d * alpha);\n"
+                + "}";
+
+        RippleView(Context c) {
+            super(c);
+            setClickable(true);
+
+            mX = CanvasProperty.createFloat(200.0f);
+            mY = CanvasProperty.createFloat(200.0f);
+            mRadius = CanvasProperty.createFloat(150.0f);
+            mProgress = CanvasProperty.createFloat(0.0f);
+
+            Paint p = new Paint();
+            p.setAntiAlias(true);
+            p.setColor(0xFFFF0000);
+            mPaint = CanvasProperty.createPaint(p);
+
+            mRuntimeShader = new RuntimeShader(sSkSL, false);
+            mRuntimeShader.setUniform("in_maxRadius", MAX_RADIUS);
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+
+            if (canvas.isHardwareAccelerated()) {
+                RecordingCanvas recordingCanvas = (RecordingCanvas) canvas;
+                recordingCanvas.drawRipple(mX, mY, mRadius, mPaint, mProgress, mRuntimeShader);
+            }
+        }
+
+        @Override
+        public boolean performClick() {
+            for (int i = 0; i < mRunningAnimations.size(); i++) {
+                mRunningAnimations.get(i).cancel();
+            }
+            mRunningAnimations.clear();
+
+            mToggle = !mToggle;
+
+            mRunningAnimations.add(new RenderNodeAnimator(
+                    mX, mToggle ? 400.0f : 200.0f));
+
+            mRunningAnimations.add(new RenderNodeAnimator(
+                    mY, mToggle ? 600.0f : 200.0f));
+
+            mRunningAnimations.add(new RenderNodeAnimator(
+                    mRadius, mToggle ? MAX_RADIUS : 150.0f));
+
+            mRunningAnimations.add(new RenderNodeAnimator(
+                    mProgress, mToggle ? 1.0f : 0.0f));
+
+            mRunningAnimations.add(new RenderNodeAnimator(
+                    mPaint, RenderNodeAnimator.PAINT_ALPHA, 64.0f));
+
+            // Will be "chained" to run after the above
+            mRunningAnimations.add(new RenderNodeAnimator(
+                    mPaint, RenderNodeAnimator.PAINT_ALPHA, 255.0f));
+
+            for (int i = 0; i < mRunningAnimations.size(); i++) {
+                RenderNodeAnimator anim = mRunningAnimations.get(i);
+                anim.setDuration(DURATION);
+                anim.setTarget(this);
+                if (i == (mRunningAnimations.size() - 1)) {
+                    // "chain" test
+                    anim.setStartValue(64.0f);
+                    anim.setStartDelay(anim.getDuration());
+                }
+                anim.start();
+            }
+
+            if (mToggle) {
+                post(new Runnable() {
+                    @Override
+                    public void run() {
+                        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "pretendBusy");
+                        try {
+                            Thread.sleep(DURATION);
+                        } catch (InterruptedException e) {
+                        }
+                        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+                    }
+                });
+            }
+            return true;
+        }
+    }
+}
diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
index 2a601e5..ad8aac1 100644
--- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
@@ -140,6 +140,21 @@
                 Install.multi(TestApp.AIncompleteSplit, TestApp.B1, TestApp.Apex1).setStaged());
     }
 
+    @Test
+    public void testFailStagedSessionIfStagingDirectoryDeleted_Commit() throws Exception {
+        int sessionId = Install.multi(TestApp.A1, TestApp.Apex1).setStaged().commit();
+        assertSessionReady(sessionId);
+        storeSessionId(sessionId);
+    }
+
+    @Test
+    public void testFailStagedSessionIfStagingDirectoryDeleted_Verify() throws Exception {
+        int sessionId = retrieveLastSessionId();
+        PackageInstaller.SessionInfo info =
+                InstallUtils.getPackageInstaller().getSessionInfo(sessionId);
+        assertThat(info.isStagedSessionFailed()).isTrue();
+    }
+
     private static void assertSessionReady(int sessionId) {
         assertSessionState(sessionId,
                 (session) -> assertThat(session.isStagedSessionReady()).isTrue());
diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
index 9e1ea2e..2201efd 100644
--- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
@@ -279,6 +279,21 @@
         assertThat(getStagingDirectories()).isEmpty();
     }
 
+    @Test
+    public void testFailStagedSessionIfStagingDirectoryDeleted() throws Exception {
+        // Create a staged session
+        runPhase("testFailStagedSessionIfStagingDirectoryDeleted_Commit");
+
+        // Delete the staging directory
+        getDevice().enableAdbRoot();
+        getDevice().executeShellCommand("rm -r /data/app-staging");
+        getDevice().disableAdbRoot();
+
+        getDevice().reboot();
+
+        runPhase("testFailStagedSessionIfStagingDirectoryDeleted_Verify");
+    }
+
     private List<String> getStagingDirectories() throws DeviceNotAvailableException {
         String baseDir = "/data/app-staging";
         try {
diff --git a/tests/WindowInsetsTests/res/values/strings.xml b/tests/WindowInsetsTests/res/values/strings.xml
index 1a236c6..d6355f5 100644
--- a/tests/WindowInsetsTests/res/values/strings.xml
+++ b/tests/WindowInsetsTests/res/values/strings.xml
@@ -23,7 +23,7 @@
     <!-- The item positions should match the flag values respectively. -->
     <string-array name="behaviors">
         <item>BEHAVIOR_SHOW_BARS_BY_TOUCH</item>
-        <item>BEHAVIOR_SHOW_BARS_BY_SWIPE</item>
+        <item>BEHAVIOR_DEFAULT</item>
         <item>BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE</item>
     </string-array>
 </resources>
diff --git a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ControllerActivity.java b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ControllerActivity.java
index beb4049..95fd959 100644
--- a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ControllerActivity.java
+++ b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ControllerActivity.java
@@ -53,6 +53,8 @@
                 R.array.behaviors, android.R.layout.simple_spinner_item);
         adapterBehavior.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
         spinnerBehavior.setAdapter(adapterBehavior);
+        spinnerBehavior.setSelection(
+                spinnerBehavior.getWindowInsetsController().getSystemBarsBehavior());
         spinnerBehavior.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
             @Override
             public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
diff --git a/tests/net/common/java/android/net/CaptivePortalDataTest.kt b/tests/net/common/java/android/net/CaptivePortalDataTest.kt
index 2cb16d3372..b2bcfeb 100644
--- a/tests/net/common/java/android/net/CaptivePortalDataTest.kt
+++ b/tests/net/common/java/android/net/CaptivePortalDataTest.kt
@@ -58,7 +58,8 @@
 
     @Test
     fun testParcelUnparcel() {
-        assertParcelSane(data, fieldCount = 8)
+        val fieldCount = if (SdkLevel.isAtLeastS()) 8 else 7
+        assertParcelSane(data, fieldCount)
 
         assertParcelingIsLossless(makeBuilder().setUserPortalUrl(null).build())
         assertParcelingIsLossless(makeBuilder().setVenueInfoUrl(null).build())
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 8e18751..16c4865 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
@@ -46,8 +46,6 @@
 import com.android.server.LocalServices
 import com.android.server.NetworkAgentWrapper
 import com.android.server.TestNetIdManager
-import com.android.server.connectivity.DefaultNetworkMetrics
-import com.android.server.connectivity.IpConnectivityMetrics
 import com.android.server.connectivity.MockableSystemProperties
 import com.android.server.connectivity.ProxyTracker
 import com.android.server.net.NetworkPolicyManagerInternal
@@ -92,10 +90,6 @@
     private lateinit var netd: INetd
     @Mock
     private lateinit var dnsResolver: IDnsResolver
-    @Mock
-    private lateinit var metricsLogger: IpConnectivityMetrics.Logger
-    @Mock
-    private lateinit var defaultMetrics: DefaultNetworkMetrics
     @Spy
     private var context = TestableContext(realContext)
 
@@ -149,7 +143,6 @@
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
-        doReturn(defaultMetrics).`when`(metricsLogger).defaultNetworkMetrics()
         doNothing().`when`(context).sendStickyBroadcastAsUser(any(), any(), any())
 
         networkStackClient = TestNetworkStackClient(realContext)
@@ -173,7 +166,6 @@
     private fun makeDependencies(): ConnectivityService.Dependencies {
         val deps = spy(ConnectivityService.Dependencies())
         doReturn(networkStackClient).`when`(deps).networkStack
-        doReturn(metricsLogger).`when`(deps).metricsLogger
         doReturn(mock(ProxyTracker::class.java)).`when`(deps).makeProxyTracker(any(), any())
         doReturn(mock(MockableSystemProperties::class.java)).`when`(deps).systemProperties
         doReturn(TestNetIdManager()).`when`(deps).makeNetIdManager()
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index a836e81..4630269 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -21,6 +21,7 @@
 import static android.app.PendingIntent.FLAG_IMMUTABLE;
 import static android.content.Intent.ACTION_USER_ADDED;
 import static android.content.Intent.ACTION_USER_REMOVED;
+import static android.content.Intent.ACTION_USER_UNLOCKED;
 import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
 import static android.content.pm.PackageManager.GET_PERMISSIONS;
 import static android.content.pm.PackageManager.MATCH_ANY_USER;
@@ -221,6 +222,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.security.Credentials;
 import android.security.KeyStore;
 import android.system.Os;
 import android.telephony.TelephonyManager;
@@ -237,14 +239,13 @@
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.net.VpnConfig;
 import com.android.internal.net.VpnInfo;
+import com.android.internal.net.VpnProfile;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.WakeupMessage;
 import com.android.internal.util.test.BroadcastInterceptingContext;
 import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.server.ConnectivityService.ConnectivityDiagnosticsCallbackInfo;
 import com.android.server.connectivity.ConnectivityConstants;
-import com.android.server.connectivity.DefaultNetworkMetrics;
-import com.android.server.connectivity.IpConnectivityMetrics;
 import com.android.server.connectivity.MockableSystemProperties;
 import com.android.server.connectivity.Nat464Xlat;
 import com.android.server.connectivity.NetworkAgentInfo;
@@ -281,6 +282,7 @@
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.Socket;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -367,8 +369,6 @@
     private HandlerThread mAlarmManagerThread;
     private TestNetIdManager mNetIdManager;
 
-    @Mock IpConnectivityMetrics.Logger mMetricsService;
-    @Mock DefaultNetworkMetrics mDefaultNetworkMetrics;
     @Mock DeviceIdleInternal mDeviceIdleInternal;
     @Mock INetworkManagementService mNetworkManagementService;
     @Mock INetworkStatsService mStatsService;
@@ -388,6 +388,7 @@
     @Mock MockableSystemProperties mSystemProperties;
     @Mock EthernetManager mEthernetManager;
     @Mock NetworkPolicyManager mNetworkPolicyManager;
+    @Mock KeyStore mKeyStore;
 
     private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
             ArgumentCaptor.forClass(ResolverParamsParcel.class);
@@ -1066,6 +1067,15 @@
         private int mVpnType = VpnManager.TYPE_VPN_SERVICE;
         private VpnInfo mVpnInfo;
 
+        // These ConditionVariables allow tests to wait for LegacyVpnRunner to be stopped/started.
+        // TODO: this scheme is ad-hoc and error-prone because it does not fail if, for example, the
+        // test expects two starts in a row, or even if the production code calls start twice in a
+        // row. find a better solution. Simply putting a method to create a LegacyVpnRunner into
+        // Vpn.Dependencies doesn't work because LegacyVpnRunner is not a static class and has
+        // extensive access into the internals of Vpn.
+        private ConditionVariable mStartLegacyVpnCv = new ConditionVariable();
+        private ConditionVariable mStopVpnRunnerCv = new ConditionVariable();
+
         public MockVpn(int userId) {
             super(startHandlerThreadAndReturnLooper(), mServiceContext,
                     new Dependencies() {
@@ -1079,7 +1089,7 @@
                             return mDeviceIdleInternal;
                         }
                     },
-                    mNetworkManagementService, mMockNetd, userId, mock(KeyStore.class));
+                    mNetworkManagementService, mMockNetd, userId, mKeyStore);
         }
 
         public void setUids(Set<UidRange> uids) {
@@ -1191,10 +1201,44 @@
             }
             mAgentRegistered = false;
             setUids(null);
+            // Remove NET_CAPABILITY_INTERNET or MockNetworkAgent will refuse to connect later on.
+            mNetworkCapabilities.removeCapability(NET_CAPABILITY_INTERNET);
             mInterface = null;
         }
 
         @Override
+        public void startLegacyVpnRunner() {
+            mStartLegacyVpnCv.open();
+        }
+
+        public void expectStartLegacyVpnRunner() {
+            assertTrue("startLegacyVpnRunner not called after " + TIMEOUT_MS + " ms",
+                    mStartLegacyVpnCv.block(TIMEOUT_MS));
+
+            // startLegacyVpn calls stopVpnRunnerPrivileged, which will open mStopVpnRunnerCv, just
+            // before calling startLegacyVpnRunner. Restore mStopVpnRunnerCv, so the test can expect
+            // that the VpnRunner is stopped and immediately restarted by calling
+            // expectStartLegacyVpnRunner() and expectStopVpnRunnerPrivileged() back-to-back.
+            mStopVpnRunnerCv = new ConditionVariable();
+        }
+
+        @Override
+        public void stopVpnRunnerPrivileged() {
+            if (mVpnRunner != null) {
+                super.stopVpnRunnerPrivileged();
+                disconnect();
+                mStartLegacyVpnCv = new ConditionVariable();
+            }
+            mVpnRunner = null;
+            mStopVpnRunnerCv.open();
+        }
+
+        public void expectStopVpnRunnerPrivileged() {
+            assertTrue("stopVpnRunnerPrivileged not called after " + TIMEOUT_MS + " ms",
+                    mStopVpnRunnerCv.block(TIMEOUT_MS));
+        }
+
+        @Override
         public synchronized VpnInfo getVpnInfo() {
             if (mVpnInfo != null) return mVpnInfo;
 
@@ -1275,10 +1319,19 @@
         }
     }
 
-    private static final int VPN_USER = 0;
-    private static final int APP1_UID = UserHandle.getUid(VPN_USER, 10100);
-    private static final int APP2_UID = UserHandle.getUid(VPN_USER, 10101);
-    private static final int VPN_UID = UserHandle.getUid(VPN_USER, 10043);
+    private static final int PRIMARY_USER = 0;
+    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);
+    private static final UserInfo PRIMARY_USER_INFO = new UserInfo(PRIMARY_USER, "",
+            UserInfo.FLAG_PRIMARY);
+
+    private static final int RESTRICTED_USER = 1;
+    private static final UserInfo RESTRICTED_USER_INFO = new UserInfo(RESTRICTED_USER, "",
+            UserInfo.FLAG_RESTRICTED);
+    static {
+        RESTRICTED_USER_INFO.restrictedProfileParentId = PRIMARY_USER;
+    }
 
     @Before
     public void setUp() throws Exception {
@@ -1287,12 +1340,14 @@
         mContext = InstrumentationRegistry.getContext();
 
         MockitoAnnotations.initMocks(this);
-        when(mMetricsService.defaultNetworkMetrics()).thenReturn(mDefaultNetworkMetrics);
 
-        when(mUserManager.getAliveUsers()).thenReturn(
-                Arrays.asList(new UserInfo[] {
-                        new UserInfo(VPN_USER, "", 0),
-                }));
+        when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO));
+        when(mUserManager.getUserInfo(PRIMARY_USER)).thenReturn(PRIMARY_USER_INFO);
+        // canHaveRestrictedProfile does not take a userId. It applies to the userId of the context
+        // it was started from, i.e., PRIMARY_USER.
+        when(mUserManager.canHaveRestrictedProfile()).thenReturn(true);
+        when(mUserManager.getUserInfo(RESTRICTED_USER)).thenReturn(RESTRICTED_USER_INFO);
+
         final ApplicationInfo applicationInfo = new ApplicationInfo();
         applicationInfo.targetSdkVersion = Build.VERSION_CODES.Q;
         when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
@@ -1362,9 +1417,9 @@
         doReturn(mNetworkStack).when(deps).getNetworkStack();
         doReturn(mSystemProperties).when(deps).getSystemProperties();
         doReturn(mock(ProxyTracker.class)).when(deps).makeProxyTracker(any(), any());
-        doReturn(mMetricsService).when(deps).getMetricsLogger();
         doReturn(true).when(deps).queryUserAccess(anyInt(), anyInt());
         doReturn(mBatteryStatsService).when(deps).getBatteryStatsService();
+        doReturn(mKeyStore).when(deps).getKeyStore();
         doAnswer(inv -> {
             mPolicyTracker = new WrappedMultinetworkPolicyTracker(
                     inv.getArgument(0), inv.getArgument(1), inv.getArgument(2));
@@ -1533,7 +1588,7 @@
             waitForIdle();
             try {
                 final Intent intent = get(timeoutMs, TimeUnit.MILLISECONDS);
-                fail("Unexpected broadcast: " + intent.getAction());
+                fail("Unexpected broadcast: " + intent.getAction() + " " + intent.getExtras());
             } catch (TimeoutException expected) {
             } finally {
                 mServiceContext.unregisterReceiver(mReceiver);
@@ -2074,10 +2129,6 @@
 
     @Test
     public void testOwnerUidCannotChange() throws Exception {
-        // Owner UIDs are not visible without location permission.
-        setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
-                Manifest.permission.ACCESS_FINE_LOCATION);
-
         final NetworkCapabilities ncTemplate = new NetworkCapabilities();
         final int originalOwnerUid = Process.myUid();
         ncTemplate.setOwnerUid(originalOwnerUid);
@@ -2097,6 +2148,10 @@
         mWiFiNetworkAgent.setNetworkCapabilities(agentCapabilities, true);
         waitForIdle();
 
+        // Owner UIDs are not visible without location permission.
+        setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
+                Manifest.permission.ACCESS_FINE_LOCATION);
+
         // Check that the capability change has been applied but the owner UID is not modified.
         NetworkCapabilities nc = mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork());
         assertEquals(originalOwnerUid, nc.getOwnerUid());
@@ -5837,6 +5892,131 @@
         mCm.unregisterNetworkCallback(callback);
     }
 
+    private void assertGetNetworkInfoOfGetActiveNetworkIsConnected(boolean expectedConnectivity) {
+        // What Chromium used to do before https://chromium-review.googlesource.com/2605304
+        assertEquals("Unexpected result for getActiveNetworkInfo(getActiveNetwork())",
+                expectedConnectivity, mCm.getNetworkInfo(mCm.getActiveNetwork()).isConnected());
+    }
+
+    @Test
+    public void testVpnUnderlyingNetworkSuspended() throws Exception {
+        final TestNetworkCallback callback = new TestNetworkCallback();
+        mCm.registerDefaultNetworkCallback(callback);
+
+        // Connect a VPN.
+        mMockVpn.establishForMyUid(false /* validated */, true /* hasInternet */,
+                false /* isStrictMode */);
+        callback.expectAvailableCallbacksUnvalidated(mMockVpn);
+
+        // Connect cellular data.
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+        mCellNetworkAgent.connect(false /* validated */);
+        callback.expectCapabilitiesThat(mMockVpn,
+                nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
+                        && nc.hasTransport(TRANSPORT_CELLULAR));
+        callback.assertNoCallback();
+
+        assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
+                .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
+        assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        assertGetNetworkInfoOfGetActiveNetworkIsConnected(true);
+
+        // Suspend the cellular network and expect the VPN to be suspended.
+        mCellNetworkAgent.suspend();
+        callback.expectCapabilitiesThat(mMockVpn,
+                nc -> !nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
+                        && nc.hasTransport(TRANSPORT_CELLULAR));
+        callback.expectCallback(CallbackEntry.SUSPENDED, mMockVpn);
+        callback.assertNoCallback();
+
+        assertFalse(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
+                .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED);
+        assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
+        assertNetworkInfo(TYPE_VPN, DetailedState.SUSPENDED);
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED);
+        // VPN's main underlying network is suspended, so no connectivity.
+        assertGetNetworkInfoOfGetActiveNetworkIsConnected(false);
+
+        // Switch to another network. The VPN should no longer be suspended.
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connect(false /* validated */);
+        callback.expectCapabilitiesThat(mMockVpn,
+                nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
+                        && nc.hasTransport(TRANSPORT_WIFI));
+
+        // BUG: the VPN is no longer suspended, so a RESUMED callback should have been sent.
+        // callback.expectCallback(CallbackEntry.RESUMED, mMockVpn);
+        callback.assertNoCallback();
+
+        assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
+                .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
+        assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_VPN, DetailedState.SUSPENDED);  // BUG: VPN caps have NOT_SUSPENDED.
+        assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+        // BUG: the device has connectivity, so this should return true.
+        assertGetNetworkInfoOfGetActiveNetworkIsConnected(false);
+
+        // Unsuspend cellular and then switch back to it.
+        // The same bug happens in the opposite direction: the VPN's capabilities correctly have
+        // NOT_SUSPENDED, but the VPN's NetworkInfo is in state SUSPENDED.
+        mCellNetworkAgent.resume();
+        callback.assertNoCallback();
+        mWiFiNetworkAgent.disconnect();
+        callback.expectCapabilitiesThat(mMockVpn,
+                nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
+                        && nc.hasTransport(TRANSPORT_CELLULAR));
+        // Spurious double callback?
+        callback.expectCapabilitiesThat(mMockVpn,
+                nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
+                        && nc.hasTransport(TRANSPORT_CELLULAR));
+        callback.assertNoCallback();
+
+        assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
+                .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
+        assertNetworkInfo(TYPE_VPN, DetailedState.SUSPENDED);  // BUG: VPN caps have NOT_SUSPENDED.
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        // BUG: the device has connectivity, so this should return true.
+        assertGetNetworkInfoOfGetActiveNetworkIsConnected(false);
+
+        // Re-suspending the current network fixes the problem.
+        mCellNetworkAgent.suspend();
+        callback.expectCapabilitiesThat(mMockVpn,
+                nc -> !nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
+                        && nc.hasTransport(TRANSPORT_CELLULAR));
+        callback.expectCallback(CallbackEntry.SUSPENDED, mMockVpn);
+        callback.assertNoCallback();
+
+        assertFalse(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
+                .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED);
+        assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
+        assertNetworkInfo(TYPE_VPN, DetailedState.SUSPENDED);
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED);
+        assertGetNetworkInfoOfGetActiveNetworkIsConnected(false);
+
+        mCellNetworkAgent.resume();
+        callback.expectCapabilitiesThat(mMockVpn,
+                nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
+                        && nc.hasTransport(TRANSPORT_CELLULAR));
+        callback.expectCallback(CallbackEntry.RESUMED, mMockVpn);
+        callback.assertNoCallback();
+
+        assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
+                .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
+        assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        assertGetNetworkInfoOfGetActiveNetworkIsConnected(true);
+    }
+
     @Test
     public void testVpnNetworkActive() throws Exception {
         final int uid = Process.myUid();
@@ -6315,7 +6495,7 @@
     }
 
     @Test
-    public void testVpnRestrictedUsers() throws Exception {
+    public void testRestrictedProfileAffectsVpnUidRanges() throws Exception {
         // NETWORK_SETTINGS is necessary to see the UID ranges in NetworkCapabilities.
         mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
                 PERMISSION_GRANTED);
@@ -6347,19 +6527,11 @@
         callback.expectCapabilitiesThat(mWiFiNetworkAgent, (caps)
                 -> caps.hasCapability(NET_CAPABILITY_VALIDATED));
 
-        // Create a fake restricted profile whose parent is our user ID.
-        final int userId = UserHandle.getUserId(uid);
-        when(mUserManager.canHaveRestrictedProfile()).thenReturn(true);
-        final int restrictedUserId = userId + 1;
-        final UserInfo info = new UserInfo(restrictedUserId, "user", UserInfo.FLAG_RESTRICTED);
-        info.restrictedProfileParentId = userId;
-        assertTrue(info.isRestricted());
-        when(mUserManager.getUserInfo(restrictedUserId)).thenReturn(info);
-        when(mPackageManager.getPackageUidAsUser(ALWAYS_ON_PACKAGE, restrictedUserId))
-                .thenReturn(UserHandle.getUid(restrictedUserId, VPN_UID));
+        when(mPackageManager.getPackageUidAsUser(ALWAYS_ON_PACKAGE, RESTRICTED_USER))
+                .thenReturn(UserHandle.getUid(RESTRICTED_USER, VPN_UID));
 
         final Intent addedIntent = new Intent(ACTION_USER_ADDED);
-        addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, restrictedUserId);
+        addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
 
         // Send a USER_ADDED broadcast for it.
         // The BroadcastReceiver for this broadcast checks that is being run on the handler thread.
@@ -6371,7 +6543,7 @@
         callback.expectCapabilitiesThat(mMockVpn, (caps)
                 -> caps.getUids().size() == 2
                 && caps.getUids().contains(new UidRange(uid, uid))
-                && caps.getUids().contains(UidRange.createForUser(restrictedUserId))
+                && caps.getUids().contains(UidRange.createForUser(RESTRICTED_USER))
                 && caps.hasTransport(TRANSPORT_VPN)
                 && caps.hasTransport(TRANSPORT_WIFI));
 
@@ -6381,13 +6553,13 @@
         callback.expectCapabilitiesThat(mMockVpn, (caps)
                 -> caps.getUids().size() == 2
                 && caps.getUids().contains(new UidRange(uid, uid))
-                && caps.getUids().contains(UidRange.createForUser(restrictedUserId))
+                && caps.getUids().contains(UidRange.createForUser(RESTRICTED_USER))
                 && caps.hasTransport(TRANSPORT_VPN)
                 && !caps.hasTransport(TRANSPORT_WIFI));
 
         // Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user.
         final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
-        removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, restrictedUserId);
+        removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
         handler.post(() -> mServiceContext.sendBroadcast(removedIntent));
 
         // Expect that the VPN gains the UID range for the restricted user, and that the capability
@@ -6397,53 +6569,72 @@
                 && caps.getUids().contains(new UidRange(uid, uid))
                 && caps.hasTransport(TRANSPORT_VPN)
                 && !caps.hasTransport(TRANSPORT_WIFI));
+    }
 
-        // Test lockdown with restricted profiles.
+    @Test
+    public void testLockdownVpnWithRestrictedProfiles() throws Exception {
+        // For ConnectivityService#setAlwaysOnVpnPackage.
         mServiceContext.setPermission(
                 Manifest.permission.CONTROL_ALWAYS_ON_VPN, PERMISSION_GRANTED);
+        // For call Vpn#setAlwaysOnPackage.
         mServiceContext.setPermission(
                 Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED);
+        // Necessary to see the UID ranges in NetworkCapabilities.
         mServiceContext.setPermission(
                 Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
 
+        final NetworkRequest request = new NetworkRequest.Builder()
+                .removeCapability(NET_CAPABILITY_NOT_VPN)
+                .build();
+        final TestNetworkCallback callback = new TestNetworkCallback();
+        mCm.registerNetworkCallback(request, callback);
+
+        final int uid = Process.myUid();
+
         // Connect wifi and check that UIDs in the main and restricted profiles have network access.
-        mMockVpn.disconnect();
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true /* validated */);
-        final int restrictedUid = UserHandle.getUid(restrictedUserId, 42 /* appId */);
+        final int restrictedUid = UserHandle.getUid(RESTRICTED_USER, 42 /* appId */);
         assertNotNull(mCm.getActiveNetworkForUid(uid));
         assertNotNull(mCm.getActiveNetworkForUid(restrictedUid));
 
         // Enable always-on VPN lockdown. The main user loses network access because no VPN is up.
         final ArrayList<String> allowList = new ArrayList<>();
-        mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
+        mService.setAlwaysOnVpnPackage(PRIMARY_USER, ALWAYS_ON_PACKAGE, true /* lockdown */,
+                allowList);
         waitForIdle();
         assertNull(mCm.getActiveNetworkForUid(uid));
+        // This is arguably overspecified: a UID that is not running doesn't have an active network.
+        // But it's useful to check that non-default users do not lose network access, and to prove
+        // that the loss of connectivity below is indeed due to the restricted profile coming up.
         assertNotNull(mCm.getActiveNetworkForUid(restrictedUid));
 
         // Start the restricted profile, and check that the UID within it loses network access.
-        when(mUserManager.getAliveUsers()).thenReturn(
-                Arrays.asList(new UserInfo[] {
-                        new UserInfo(userId, "", 0),
-                        info
-                }));
+        when(mPackageManager.getPackageUidAsUser(ALWAYS_ON_PACKAGE, RESTRICTED_USER))
+                .thenReturn(UserHandle.getUid(RESTRICTED_USER, VPN_UID));
+        when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO,
+                RESTRICTED_USER_INFO));
         // TODO: check that VPN app within restricted profile still has access, etc.
+        final Intent addedIntent = new Intent(ACTION_USER_ADDED);
+        addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
+        final Handler handler = new Handler(mCsHandlerThread.getLooper());
         handler.post(() -> mServiceContext.sendBroadcast(addedIntent));
         waitForIdle();
         assertNull(mCm.getActiveNetworkForUid(uid));
         assertNull(mCm.getActiveNetworkForUid(restrictedUid));
 
         // Stop the restricted profile, and check that the UID within it has network access again.
-        when(mUserManager.getAliveUsers()).thenReturn(
-                Arrays.asList(new UserInfo[] {
-                        new UserInfo(userId, "", 0),
-                }));
+        when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO));
+
+        // Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user.
+        final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
+        removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
         handler.post(() -> mServiceContext.sendBroadcast(removedIntent));
         waitForIdle();
         assertNull(mCm.getActiveNetworkForUid(uid));
         assertNotNull(mCm.getActiveNetworkForUid(restrictedUid));
 
-        mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
+        mService.setAlwaysOnVpnPackage(PRIMARY_USER, null, false /* lockdown */, allowList);
         waitForIdle();
     }
 
@@ -6784,6 +6975,7 @@
         final int userId = UserHandle.getUserId(uid);
         final ArrayList<String> allowList = new ArrayList<>();
         mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
+        waitForIdle();
 
         UidRangeParcel firstHalf = new UidRangeParcel(1, VPN_UID - 1);
         UidRangeParcel secondHalf = new UidRangeParcel(VPN_UID + 1, 99999);
@@ -6805,10 +6997,10 @@
 
         // Disable lockdown, expect to see the network unblocked.
         mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
-        expectNetworkRejectNonSecureVpn(inOrder, false, firstHalf, secondHalf);
         callback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
         defaultCallback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
         vpnUidCallback.assertNoCallback();
+        expectNetworkRejectNonSecureVpn(inOrder, false, firstHalf, secondHalf);
         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
         assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
@@ -6851,9 +7043,11 @@
         // Disable lockdown, remove our UID from the allowlist, and re-enable lockdown.
         // Everything should now be blocked.
         mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
+        waitForIdle();
         expectNetworkRejectNonSecureVpn(inOrder, false, piece1, piece2, piece3);
         allowList.clear();
         mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
+        waitForIdle();
         expectNetworkRejectNonSecureVpn(inOrder, true, firstHalf, secondHalf);
         defaultCallback.expectBlockedStatusCallback(true, mWiFiNetworkAgent);
         assertBlockedCallbackInAnyOrder(callback, true, mWiFiNetworkAgent, mCellNetworkAgent);
@@ -6931,6 +7125,200 @@
         mCm.unregisterNetworkCallback(vpnUidCallback);
     }
 
+    private void setupLegacyLockdownVpn() {
+        final String profileName = "testVpnProfile";
+        final byte[] profileTag = profileName.getBytes(StandardCharsets.UTF_8);
+        when(mKeyStore.contains(Credentials.LOCKDOWN_VPN)).thenReturn(true);
+        when(mKeyStore.get(Credentials.LOCKDOWN_VPN)).thenReturn(profileTag);
+
+        final VpnProfile profile = new VpnProfile(profileName);
+        profile.name = "My VPN";
+        profile.server = "192.0.2.1";
+        profile.dnsServers = "8.8.8.8";
+        profile.type = VpnProfile.TYPE_IPSEC_XAUTH_PSK;
+        final byte[] encodedProfile = profile.encode();
+        when(mKeyStore.get(Credentials.VPN + profileName)).thenReturn(encodedProfile);
+    }
+
+    @Test
+    public void testLegacyLockdownVpn() throws Exception {
+        mServiceContext.setPermission(
+                Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED);
+
+        final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
+        final TestNetworkCallback callback = new TestNetworkCallback();
+        mCm.registerNetworkCallback(request, callback);
+
+        final TestNetworkCallback defaultCallback = new TestNetworkCallback();
+        mCm.registerDefaultNetworkCallback(defaultCallback);
+
+        // Pretend lockdown VPN was configured.
+        setupLegacyLockdownVpn();
+
+        // LockdownVpnTracker disables the Vpn teardown code and enables lockdown.
+        // Check the VPN's state before it does so.
+        assertTrue(mMockVpn.getEnableTeardown());
+        assertFalse(mMockVpn.getLockdown());
+
+        // Send a USER_UNLOCKED broadcast so CS starts LockdownVpnTracker.
+        final int userId = UserHandle.getUserId(Process.myUid());
+        final Intent addedIntent = new Intent(ACTION_USER_UNLOCKED);
+        addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+        final Handler handler = new Handler(mCsHandlerThread.getLooper());
+        handler.post(() -> mServiceContext.sendBroadcast(addedIntent));
+        waitForIdle();
+
+        // Lockdown VPN disables teardown and enables lockdown.
+        assertFalse(mMockVpn.getEnableTeardown());
+        assertTrue(mMockVpn.getLockdown());
+
+        // Bring up a network.
+        // Expect nothing to happen because the network does not have an IPv4 default route: legacy
+        // VPN only supports IPv4.
+        final LinkProperties cellLp = new LinkProperties();
+        cellLp.setInterfaceName("rmnet0");
+        cellLp.addLinkAddress(new LinkAddress("2001:db8::1/64"));
+        cellLp.addRoute(new RouteInfo(new IpPrefix("::/0"), null, "rmnet0"));
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
+        mCellNetworkAgent.connect(false /* validated */);
+        callback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
+        defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
+        waitForIdle();
+        assertNull(mMockVpn.getAgent());
+
+        // Add an IPv4 address. Ideally the VPN should start, but it doesn't because nothing calls
+        // LockdownVpnTracker#handleStateChangedLocked. This is a bug.
+        // TODO: consider fixing this.
+        cellLp.addLinkAddress(new LinkAddress("192.0.2.2/25"));
+        cellLp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0"), null, "rmnet0"));
+        mCellNetworkAgent.sendLinkProperties(cellLp);
+        callback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
+        defaultCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
+        waitForIdle();
+        assertNull(mMockVpn.getAgent());
+
+        // Disconnect, then try again with a network that supports IPv4 at connection time.
+        // Expect lockdown VPN to come up.
+        ExpectedBroadcast b1 = expectConnectivityAction(TYPE_MOBILE, DetailedState.DISCONNECTED);
+        mCellNetworkAgent.disconnect();
+        callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+        defaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+        b1.expectBroadcast();
+
+        // When lockdown VPN is active, the NetworkInfo state in CONNECTIVITY_ACTION is overwritten
+        // with the state of the VPN network. So expect a CONNECTING broadcast.
+        b1 = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTING);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
+        mCellNetworkAgent.connect(false /* validated */);
+        callback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
+        defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
+        b1.expectBroadcast();
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
+        assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
+        assertNetworkInfo(TYPE_VPN, DetailedState.BLOCKED);
+
+        // TODO: it would be nice if we could simply rely on the production code here, and have
+        // LockdownVpnTracker start the VPN, have the VPN code register its NetworkAgent with
+        // ConnectivityService, etc. That would require duplicating a fair bit of code from the
+        // Vpn tests around how to mock out LegacyVpnRunner. But even if we did that, this does not
+        // work for at least two reasons:
+        // 1. In this test, calling registerNetworkAgent does not actually result in an agent being
+        //    registered. This is because nothing calls onNetworkMonitorCreated, which is what
+        //    actually ends up causing handleRegisterNetworkAgent to be called. Code in this test
+        //    that wants to register an agent must use TestNetworkAgentWrapper.
+        // 2. Even if we exposed Vpn#agentConnect to the test, and made MockVpn#agentConnect call
+        //    the TestNetworkAgentWrapper code, this would deadlock because the
+        //    TestNetworkAgentWrapper code cannot be called on the handler thread since it calls
+        //    waitForIdle().
+        mMockVpn.expectStartLegacyVpnRunner();
+        b1 = expectConnectivityAction(TYPE_VPN, DetailedState.CONNECTED);
+        ExpectedBroadcast b2 = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTED);
+        mMockVpn.establishForMyUid();
+        callback.expectAvailableThenValidatedCallbacks(mMockVpn);
+        defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
+        b1.expectBroadcast();
+        b2.expectBroadcast();
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
+        assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
+
+        // Switch default network from cell to wifi. Expect VPN to disconnect and reconnect.
+        final LinkProperties wifiLp = new LinkProperties();
+        wifiLp.setInterfaceName("wlan0");
+        wifiLp.addLinkAddress(new LinkAddress("192.0.2.163/25"));
+        wifiLp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0"), null, "wlan0"));
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp);
+
+        b1 = expectConnectivityAction(TYPE_MOBILE, DetailedState.DISCONNECTED);
+        // Wifi is CONNECTING because the VPN isn't up yet.
+        b2 = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTING);
+        ExpectedBroadcast b3 = expectConnectivityAction(TYPE_VPN, DetailedState.DISCONNECTED);
+        mWiFiNetworkAgent.connect(false /* validated */);
+        b1.expectBroadcast();
+        b2.expectBroadcast();
+        b3.expectBroadcast();
+        mMockVpn.expectStopVpnRunnerPrivileged();
+        mMockVpn.expectStartLegacyVpnRunner();
+
+        // TODO: why is wifi not blocked? Is it because when this callback is sent, the VPN is still
+        // connected, so the network is not considered blocked by the lockdown UID ranges? But the
+        // fact that a VPN is connected should only result in the VPN itself being unblocked, not
+        // any other network. Bug in isUidBlockedByVpn?
+        callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+        callback.expectCapabilitiesThat(mMockVpn, nc -> nc.hasTransport(TRANSPORT_WIFI));
+        callback.expectCallback(CallbackEntry.LOST, mMockVpn);
+        defaultCallback.expectCapabilitiesThat(mMockVpn, nc -> nc.hasTransport(TRANSPORT_WIFI));
+        defaultCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
+        defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent);
+
+        // While the VPN is reconnecting on the new network, everything is blocked.
+        assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
+        assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
+        assertNetworkInfo(TYPE_VPN, DetailedState.BLOCKED);
+
+        // The VPN comes up again on wifi.
+        b1 = expectConnectivityAction(TYPE_VPN, DetailedState.CONNECTED);
+        b2 = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
+        mMockVpn.establishForMyUid();
+        callback.expectAvailableThenValidatedCallbacks(mMockVpn);
+        defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
+        b1.expectBroadcast();
+        b2.expectBroadcast();
+
+        assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
+        assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
+
+        // Disconnect cell. Nothing much happens since it's not the default network.
+        // Whenever LockdownVpnTracker is connected, it will send a connected broadcast any time any
+        // NetworkInfo is updated. This is probably a bug.
+        // TODO: consider fixing this.
+        b1 = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
+        mCellNetworkAgent.disconnect();
+        b1.expectBroadcast();
+        callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+        defaultCallback.assertNoCallback();
+
+        assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
+        assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
+
+        b1 = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED);
+        mWiFiNetworkAgent.disconnect();
+        callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
+        b1.expectBroadcast();
+        callback.expectCapabilitiesThat(mMockVpn, nc -> !nc.hasTransport(TRANSPORT_WIFI));
+        b2 = expectConnectivityAction(TYPE_VPN, DetailedState.DISCONNECTED);
+        mMockVpn.expectStopVpnRunnerPrivileged();
+        callback.expectCallback(CallbackEntry.LOST, mMockVpn);
+        b2.expectBroadcast();
+    }
+
     @Test
     public final void testLoseTrusted() throws Exception {
         final NetworkRequest trustedRequest = new NetworkRequest.Builder()
@@ -7605,7 +7993,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(UidRange.createForUser(VPN_USER));
+        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
         mMockVpn.establish(lp, VPN_UID, vpnRange);
         assertVpnUidRangesUpdated(true, vpnRange, VPN_UID);
 
@@ -7633,7 +8021,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(UidRange.createForUser(VPN_USER));
+        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
         mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange);
         assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID);
 
@@ -7649,7 +8037,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(UidRange.createForUser(VPN_USER));
+        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
         mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange);
         assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID);
 
@@ -7664,7 +8052,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(UidRange.createForUser(VPN_USER));
+        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
         mMockVpn.establish(lp, VPN_UID, vpnRange);
         assertVpnUidRangesUpdated(true, vpnRange, VPN_UID);
 
@@ -7716,7 +8104,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 = UidRange.createForUser(VPN_USER);
+        final UidRange vpnRange = UidRange.createForUser(PRIMARY_USER);
         final Set<UidRange> vpnRanges = Collections.singleton(vpnRange);
         mMockVpn.establish(lp, VPN_UID, vpnRanges);
         assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID);
@@ -7781,8 +8169,22 @@
         naExtraInfo.unregister();
     }
 
+    // To avoid granting location permission bypass.
+    private void denyAllLocationPrivilegedPermissions() {
+        mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+                PERMISSION_DENIED);
+        mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
+                PERMISSION_DENIED);
+        mServiceContext.setPermission(Manifest.permission.NETWORK_STACK,
+                PERMISSION_DENIED);
+        mServiceContext.setPermission(Manifest.permission.NETWORK_SETUP_WIZARD,
+                PERMISSION_DENIED);
+    }
+
     private void setupLocationPermissions(
             int targetSdk, boolean locationToggle, String op, String perm) throws Exception {
+        denyAllLocationPrivilegedPermissions();
+
         final ApplicationInfo applicationInfo = new ApplicationInfo();
         applicationInfo.targetSdkVersion = targetSdk;
         when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
@@ -7900,7 +8302,7 @@
 
     private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
             throws Exception {
-        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
+        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
         mMockVpn.establish(new LinkProperties(), vpnOwnerUid, vpnRange);
         assertVpnUidRangesUpdated(true, vpnRange, vpnOwnerUid);
         mMockVpn.setVpnType(vpnType);
@@ -8104,11 +8506,18 @@
         assertTrue(mService.mConnectivityDiagnosticsCallbacks.containsKey(mIBinder));
     }
 
+    public NetworkAgentInfo fakeMobileNai(NetworkCapabilities nc) {
+        final NetworkInfo info = new NetworkInfo(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_LTE,
+                ConnectivityManager.getNetworkTypeName(TYPE_MOBILE),
+                TelephonyManager.getNetworkTypeName(TelephonyManager.NETWORK_TYPE_LTE));
+        return new NetworkAgentInfo(null, new Network(NET_ID), info, new LinkProperties(),
+                nc, 0, mServiceContext, null, new NetworkAgentConfig(), mService, null, null, null,
+                0, INVALID_UID);
+    }
+
     @Test
     public void testCheckConnectivityDiagnosticsPermissionsNetworkStack() throws Exception {
-        final NetworkAgentInfo naiWithoutUid =
-                new NetworkAgentInfo(null, null, null, null, new NetworkCapabilities(), 0,
-                        mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
+        final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities());
 
         mServiceContext.setPermission(
                 android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
@@ -8121,9 +8530,7 @@
 
     @Test
     public void testCheckConnectivityDiagnosticsPermissionsWrongUidPackageName() throws Exception {
-        final NetworkAgentInfo naiWithoutUid =
-                new NetworkAgentInfo(null, null, null, null, new NetworkCapabilities(), 0,
-                        mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
+        final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities());
 
         mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
 
@@ -8136,9 +8543,7 @@
 
     @Test
     public void testCheckConnectivityDiagnosticsPermissionsNoLocationPermission() throws Exception {
-        final NetworkAgentInfo naiWithoutUid =
-                new NetworkAgentInfo(null, null, null, null, new NetworkCapabilities(), 0,
-                        mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
+        final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities());
 
         mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
 
@@ -8151,22 +8556,17 @@
 
     @Test
     public void testCheckConnectivityDiagnosticsPermissionsActiveVpn() throws Exception {
-        final Network network = new Network(NET_ID);
-        final NetworkAgentInfo naiWithoutUid =
-                new NetworkAgentInfo(null, network, null, null, new NetworkCapabilities(), 0,
-                        mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
-
-        setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
-                Manifest.permission.ACCESS_FINE_LOCATION);
+        final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities());
 
         mMockVpn.establishForMyUid();
         assertUidRangesUpdatedForMyUid(true);
 
         // Wait for networks to connect and broadcasts to be sent before removing permissions.
         waitForIdle();
-        mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
+        setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
+                Manifest.permission.ACCESS_FINE_LOCATION);
 
-        assertTrue(mService.setUnderlyingNetworksForVpn(new Network[] {network}));
+        assertTrue(mService.setUnderlyingNetworksForVpn(new Network[] {naiWithoutUid.network}));
         waitForIdle();
         assertTrue(
                 "Active VPN permission not applied",
@@ -8187,9 +8587,7 @@
     public void testCheckConnectivityDiagnosticsPermissionsNetworkAdministrator() throws Exception {
         final NetworkCapabilities nc = new NetworkCapabilities();
         nc.setAdministratorUids(new int[] {Process.myUid()});
-        final NetworkAgentInfo naiWithUid =
-                new NetworkAgentInfo(null, null, null, null, nc, 0, mServiceContext, null, null,
-                        mService, null, null, null, 0, INVALID_UID);
+        final NetworkAgentInfo naiWithUid = fakeMobileNai(nc);
 
         setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
                 Manifest.permission.ACCESS_FINE_LOCATION);
@@ -8206,9 +8604,7 @@
         final NetworkCapabilities nc = new NetworkCapabilities();
         nc.setOwnerUid(Process.myUid());
         nc.setAdministratorUids(new int[] {Process.myUid()});
-        final NetworkAgentInfo naiWithUid =
-                new NetworkAgentInfo(null, null, null, null, nc, 0, mServiceContext, null, null,
-                        mService, null, null, null, 0, INVALID_UID);
+        final NetworkAgentInfo naiWithUid = fakeMobileNai(nc);
 
         setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
                 Manifest.permission.ACCESS_FINE_LOCATION);
@@ -8475,7 +8871,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 = UidRange.createForUser(VPN_USER);
+        final UidRange vpnRange = UidRange.createForUser(PRIMARY_USER);
         Set<UidRange> vpnRanges = Collections.singleton(vpnRange);
         mMockVpn.establish(lp, VPN_UID, vpnRanges);
         assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID);
@@ -8491,4 +8887,20 @@
         assertVpnUidRangesUpdated(true, newRanges, VPN_UID);
         assertVpnUidRangesUpdated(false, vpnRanges, VPN_UID);
     }
+
+    @Test
+    public void testInvalidRequestTypes() {
+        final int[] invalidReqTypeInts = new int[] {-1, NetworkRequest.Type.NONE.ordinal(),
+                NetworkRequest.Type.LISTEN.ordinal(), NetworkRequest.Type.values().length};
+        final NetworkCapabilities nc = new NetworkCapabilities().addTransportType(TRANSPORT_WIFI);
+
+        for (int reqTypeInt : invalidReqTypeInts) {
+            assertThrows("Expect throws for invalid request type " + reqTypeInt,
+                    IllegalArgumentException.class,
+                    () -> mService.requestNetwork(nc, reqTypeInt, null, 0, null,
+                            ConnectivityManager.TYPE_NONE, mContext.getPackageName(),
+                            getAttributionTag())
+            );
+        }
+    }
 }
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 96c56e3..4d151af 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -34,7 +34,9 @@
 import android.net.ConnectivityManager;
 import android.net.IDnsResolver;
 import android.net.INetd;
+import android.net.LinkProperties;
 import android.net.Network;
+import android.net.NetworkAgentConfig;
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
 import android.net.NetworkProvider;
@@ -353,9 +355,10 @@
         NetworkCapabilities caps = new NetworkCapabilities();
         caps.addCapability(0);
         caps.addTransportType(transport);
-        NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info, null,
-                caps, 50, mCtx, null, null /* config */, mConnService, mNetd, mDnsResolver, mNMS,
-                NetworkProvider.ID_NONE, Binder.getCallingUid());
+        NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info,
+                new LinkProperties(), caps, 50, mCtx, null, new NetworkAgentConfig() /* config */,
+                mConnService, mNetd, mDnsResolver, mNMS, NetworkProvider.ID_NONE,
+                Binder.getCallingUid());
         nai.everValidated = true;
         return nai;
     }
diff --git a/tests/vcn/Android.bp b/tests/vcn/Android.bp
index 3c08d34..c04ddd7 100644
--- a/tests/vcn/Android.bp
+++ b/tests/vcn/Android.bp
@@ -16,6 +16,7 @@
         "frameworks-base-testutils",
         "framework-protos",
         "mockito-target-minus-junit4",
+        "net-tests-utils",
         "platform-test-annotations",
         "services.core",
     ],
diff --git a/tests/vcn/java/android/net/vcn/VcnManagerTest.java b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
new file mode 100644
index 0000000..9c6b719
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.net.vcn;
+
+import static androidx.test.InstrumentationRegistry.getContext;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.net.vcn.VcnManager.VcnUnderlyingNetworkPolicyListener;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import java.util.concurrent.Executor;
+
+public class VcnManagerTest {
+    private static final Executor INLINE_EXECUTOR = Runnable::run;
+
+    private IVcnManagementService mMockVcnManagementService;
+    private VcnUnderlyingNetworkPolicyListener mMockPolicyListener;
+
+    private Context mContext;
+    private VcnManager mVcnManager;
+
+    @Before
+    public void setUp() {
+        mMockVcnManagementService = mock(IVcnManagementService.class);
+        mMockPolicyListener = mock(VcnUnderlyingNetworkPolicyListener.class);
+
+        mContext = getContext();
+        mVcnManager = new VcnManager(mContext, mMockVcnManagementService);
+    }
+
+    @Test
+    public void testAddVcnUnderlyingNetworkPolicyListener() throws Exception {
+        mVcnManager.addVcnUnderlyingNetworkPolicyListener(INLINE_EXECUTOR, mMockPolicyListener);
+
+        ArgumentCaptor<IVcnUnderlyingNetworkPolicyListener> captor =
+                ArgumentCaptor.forClass(IVcnUnderlyingNetworkPolicyListener.class);
+        verify(mMockVcnManagementService).addVcnUnderlyingNetworkPolicyListener(captor.capture());
+
+        assertTrue(VcnManager.REGISTERED_POLICY_LISTENERS.containsKey(mMockPolicyListener));
+
+        IVcnUnderlyingNetworkPolicyListener listenerWrapper = captor.getValue();
+        listenerWrapper.onPolicyChanged();
+        verify(mMockPolicyListener).onPolicyChanged();
+    }
+
+    @Test
+    public void testRemoveVcnUnderlyingNetworkPolicyListener() throws Exception {
+        mVcnManager.addVcnUnderlyingNetworkPolicyListener(INLINE_EXECUTOR, mMockPolicyListener);
+
+        mVcnManager.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+        assertFalse(VcnManager.REGISTERED_POLICY_LISTENERS.containsKey(mMockPolicyListener));
+        verify(mMockVcnManagementService)
+                .addVcnUnderlyingNetworkPolicyListener(
+                        any(IVcnUnderlyingNetworkPolicyListener.class));
+    }
+
+    @Test
+    public void testRemoveVcnUnderlyingNetworkPolicyListenerUnknownListener() throws Exception {
+        mVcnManager.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+        assertFalse(VcnManager.REGISTERED_POLICY_LISTENERS.containsKey(mMockPolicyListener));
+        verify(mMockVcnManagementService, never())
+                .addVcnUnderlyingNetworkPolicyListener(
+                        any(IVcnUnderlyingNetworkPolicyListener.class));
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testAddVcnUnderlyingNetworkPolicyListenerNullExecutor() throws Exception {
+        mVcnManager.addVcnUnderlyingNetworkPolicyListener(null, mMockPolicyListener);
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testAddVcnUnderlyingNetworkPolicyListenerNullListener() throws Exception {
+        mVcnManager.addVcnUnderlyingNetworkPolicyListener(INLINE_EXECUTOR, null);
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testRemoveVcnUnderlyingNetworkPolicyListenerNullListener() {
+        mVcnManager.removeVcnUnderlyingNetworkPolicyListener(null);
+    }
+}
diff --git a/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java
new file mode 100644
index 0000000..3ba0a1f
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java
@@ -0,0 +1,51 @@
+/*
+ * 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.net.vcn;
+
+import static com.android.testutils.ParcelUtils.assertParcelSane;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.net.NetworkCapabilities;
+
+import org.junit.Test;
+
+public class VcnUnderlyingNetworkPolicyTest {
+    private static final VcnUnderlyingNetworkPolicy DEFAULT_NETWORK_POLICY =
+            new VcnUnderlyingNetworkPolicy(
+                    false /* isTearDownRequested */, new NetworkCapabilities());
+    private static final VcnUnderlyingNetworkPolicy SAMPLE_NETWORK_POLICY =
+            new VcnUnderlyingNetworkPolicy(
+                    true /* isTearDownRequested */,
+                    new NetworkCapabilities.Builder()
+                            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+                            .build());
+
+    @Test
+    public void testEquals() {
+        assertEquals(DEFAULT_NETWORK_POLICY, DEFAULT_NETWORK_POLICY);
+        assertEquals(SAMPLE_NETWORK_POLICY, SAMPLE_NETWORK_POLICY);
+
+        assertNotEquals(DEFAULT_NETWORK_POLICY, SAMPLE_NETWORK_POLICY);
+    }
+
+    @Test
+    public void testParcelUnparcel() {
+        assertParcelSane(SAMPLE_NETWORK_POLICY, 2);
+    }
+}