Merge "Adding Battery saver policy to alarms"
diff --git a/MULTIUSER_OWNERS b/MULTIUSER_OWNERS
new file mode 100644
index 0000000..fbc611a
--- /dev/null
+++ b/MULTIUSER_OWNERS
@@ -0,0 +1,4 @@
+# OWNERS of Multiuser related files
+bookatz@google.com
+omakoto@google.com
+yamasani@google.com
diff --git a/apex/appsearch/framework/api/current.txt b/apex/appsearch/framework/api/current.txt
index ae9e7ff..ae32fba 100644
--- a/apex/appsearch/framework/api/current.txt
+++ b/apex/appsearch/framework/api/current.txt
@@ -100,6 +100,7 @@
     method public long getCreationTimestampMillis();
     method public static int getMaxIndexedProperties();
     method @NonNull public String getNamespace();
+    method @Nullable public Object getProperty(@NonNull String);
     method public boolean getPropertyBoolean(@NonNull String);
     method @Nullable public boolean[] getPropertyBooleanArray(@NonNull String);
     method @Nullable public byte[] getPropertyBytes(@NonNull String);
@@ -148,6 +149,12 @@
     method @NonNull public android.app.appsearch.GetByUriRequest.Builder setNamespace(@NonNull String);
   }
 
+  public class PackageIdentifier {
+    ctor public PackageIdentifier(@NonNull String, @NonNull byte[]);
+    method @NonNull public String getPackageName();
+    method @NonNull public byte[] getSha256Certificate();
+  }
+
   public final class PutDocumentsRequest {
     method @NonNull public java.util.List<android.app.appsearch.GenericDocument> getDocuments();
   }
@@ -233,6 +240,8 @@
 
   public final class SetSchemaRequest {
     method @NonNull public java.util.Set<android.app.appsearch.AppSearchSchema> getSchemas();
+    method @NonNull public java.util.Set<java.lang.String> getSchemasNotVisibleToSystemUi();
+    method @NonNull public java.util.Map<java.lang.String,java.util.Set<android.app.appsearch.PackageIdentifier>> getSchemasVisibleToPackages();
     method public boolean isForceOverride();
   }
 
@@ -242,6 +251,17 @@
     method @NonNull public android.app.appsearch.SetSchemaRequest.Builder addSchema(@NonNull java.util.Collection<android.app.appsearch.AppSearchSchema>);
     method @NonNull public android.app.appsearch.SetSchemaRequest build();
     method @NonNull public android.app.appsearch.SetSchemaRequest.Builder setForceOverride(boolean);
+    method @NonNull public android.app.appsearch.SetSchemaRequest.Builder setSchemaTypeVisibilityForPackage(@NonNull String, boolean, @NonNull android.app.appsearch.PackageIdentifier);
+    method @NonNull public android.app.appsearch.SetSchemaRequest.Builder setSchemaTypeVisibilityForSystemUi(@NonNull String, boolean);
+  }
+
+}
+
+package android.app.appsearch.exceptions {
+
+  public class AppSearchException extends java.lang.Exception {
+    method public int getResultCode();
+    method @NonNull public <T> android.app.appsearch.AppSearchResult<T> toAppSearchResult();
   }
 
 }
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java b/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
index 85207f7..11e7fab 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
@@ -20,7 +20,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SuppressLint;
-import android.app.appsearch.exceptions.AppSearchException;
 import android.app.appsearch.util.BundleUtil;
 import android.os.Bundle;
 import android.util.Log;
@@ -92,9 +91,7 @@
     /** Contains {@link GenericDocument} basic information (uri, schemaType etc). */
     @NonNull final Bundle mBundle;
 
-    /**
-     * Contains all properties in {@link GenericDocument} to support getting properties via keys.
-     */
+    /** Contains all properties in {@link GenericDocument} to support getting properties via keys */
     @NonNull private final Bundle mProperties;
 
     @NonNull private final String mUri;
@@ -202,6 +199,24 @@
     }
 
     /**
+     * Retrieves the property value with the given key as {@link Object}.
+     *
+     * @param key The key to look for.
+     * @return The entry with the given key as an object or {@code null} if there is no such key.
+     */
+    @Nullable
+    public Object getProperty(@NonNull String key) {
+        Preconditions.checkNotNull(key);
+        Object property = mProperties.get(key);
+        if (property instanceof ArrayList) {
+            return getPropertyBytesArray(key);
+        } else if (property instanceof Bundle[]) {
+            return getPropertyDocumentArray(key);
+        }
+        return property;
+    }
+
+    /**
      * Retrieves a {@link String} value by key.
      *
      * @param key The key to look for.
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/PackageIdentifier.java b/apex/appsearch/framework/java/external/android/app/appsearch/PackageIdentifier.java
index 8b20c09..43be442 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/PackageIdentifier.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/PackageIdentifier.java
@@ -23,10 +23,7 @@
 import java.util.Arrays;
 import java.util.Objects;
 
-/**
- * This class represents a uniquely identifiable package.
- * @hide
- */
+/** This class represents a uniquely identifiable package. */
 public class PackageIdentifier {
     private final String mPackageName;
     private final byte[] mSha256Certificate;
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java
index 1c360a6..b9503ee 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java
@@ -18,7 +18,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.SuppressLint;
-import android.app.appsearch.exceptions.AppSearchException;
 
 import com.android.internal.util.Preconditions;
 
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 5ffa7c9..eb0b7324 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java
@@ -49,31 +49,20 @@
     /** @hide */
     public static final String MATCHES_FIELD = "matches";
 
-    @NonNull private final Bundle mBundle;
+    /** @hide */
+    public static final String PACKAGE_NAME_FIELD = "packageName";
 
-    @NonNull private final Bundle mDocumentBundle;
+    @NonNull private final Bundle mBundle;
 
     /** Cache of the inflated document. Comes from inflating mDocumentBundle at first use. */
     @Nullable private GenericDocument mDocument;
 
-    /**
-     * Contains a list of MatchInfo bundles that matched the request.
-     *
-     * <p>Only populated when requested in both {@link SearchSpec.Builder#setSnippetCount} and
-     * {@link SearchSpec.Builder#setSnippetCountPerProperty}.
-     *
-     * @see #getMatches()
-     */
-    @NonNull private final List<Bundle> mMatchBundles;
-
     /** Cache of the inflated matches. Comes from inflating mMatchBundles at first use. */
     @Nullable private List<MatchInfo> mMatches;
 
     /** @hide */
     public SearchResult(@NonNull Bundle bundle) {
         mBundle = Preconditions.checkNotNull(bundle);
-        mDocumentBundle = Preconditions.checkNotNull(bundle.getBundle(DOCUMENT_FIELD));
-        mMatchBundles = Preconditions.checkNotNull(bundle.getParcelableArrayList(MATCHES_FIELD));
     }
 
     /** @hide */
@@ -90,7 +79,9 @@
     @NonNull
     public GenericDocument getDocument() {
         if (mDocument == null) {
-            mDocument = new GenericDocument(mDocumentBundle);
+            mDocument =
+                    new GenericDocument(
+                            Preconditions.checkNotNull(mBundle.getBundle(DOCUMENT_FIELD)));
         }
         return mDocument;
     }
@@ -106,9 +97,11 @@
     @NonNull
     public List<MatchInfo> getMatches() {
         if (mMatches == null) {
-            mMatches = new ArrayList<>(mMatchBundles.size());
-            for (int i = 0; i < mMatchBundles.size(); i++) {
-                MatchInfo matchInfo = new MatchInfo(getDocument(), mMatchBundles.get(i));
+            List<Bundle> matchBundles =
+                    Preconditions.checkNotNull(mBundle.getParcelableArrayList(MATCHES_FIELD));
+            mMatches = new ArrayList<>(matchBundles.size());
+            for (int i = 0; i < matchBundles.size(); i++) {
+                MatchInfo matchInfo = new MatchInfo(getDocument(), matchBundles.get(i));
                 mMatches.add(matchInfo);
             }
         }
@@ -116,6 +109,17 @@
     }
 
     /**
+     * Contains the package name that stored the {@link GenericDocument}.
+     *
+     * @return Package name that stored the document
+     * @hide
+     */
+    @NonNull
+    public String getPackageName() {
+        return Preconditions.checkNotNull(mBundle.getString(PACKAGE_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/framework/java/external/android/app/appsearch/SearchSpec.java b/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java
index 400b630..c3f0d8a 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java
@@ -19,8 +19,6 @@
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
-import android.annotation.SuppressLint;
-import android.app.appsearch.exceptions.AppSearchException;
 import android.app.appsearch.exceptions.IllegalSearchSpecException;
 import android.os.Bundle;
 import android.util.ArrayMap;
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
index ad3ee05..e9c4cb4 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
@@ -59,7 +59,6 @@
 
     /**
      * Returns the set of schema types that have opted out of being visible on system UI surfaces.
-     * @hide
      */
     @NonNull
     public Set<String> getSchemasNotVisibleToSystemUi() {
@@ -72,7 +71,6 @@
      * certificate.
      *
      * <p>This method is inefficient to call repeatedly.
-     * @hide
      */
     @NonNull
     public Map<String, Set<PackageIdentifier>> getSchemasVisibleToPackages() {
@@ -141,7 +139,6 @@
          *
          * @param schemaType The schema type to set visibility on.
          * @param visible Whether the {@code schemaType} will be visible or not.
-         * @hide
          */
         // Merged list available from getSchemasNotVisibleToSystemUi
         @SuppressLint("MissingGetterMatchingBuilder")
@@ -165,7 +162,6 @@
          * @param schemaType The schema type to set visibility on.
          * @param visible Whether the {@code schemaType} will be visible or not.
          * @param packageIdentifier Represents the package that will be granted visibility.
-         * @hide
          */
         // Merged list available from getSchemasVisibleToPackages
         @SuppressLint("MissingGetterMatchingBuilder")
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/exceptions/AppSearchException.java b/apex/appsearch/framework/java/external/android/app/appsearch/exceptions/AppSearchException.java
index 704f180..b1a33a4 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/exceptions/AppSearchException.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/exceptions/AppSearchException.java
@@ -25,8 +25,6 @@
  *
  * <p>These exceptions can be converted into a failed {@link AppSearchResult} for propagating to the
  * client.
- *
- * @hide
  */
 public class AppSearchException extends Exception {
     private final @AppSearchResult.ResultCode int mResultCode;
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 47a81eb..a2126b1 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
@@ -37,6 +37,7 @@
 import com.android.server.appsearch.external.localstorage.converter.SearchSpecToProtoConverter;
 
 import com.google.android.icing.IcingSearchEngine;
+import com.google.android.icing.proto.DeleteByQueryResultProto;
 import com.google.android.icing.proto.DeleteResultProto;
 import com.google.android.icing.proto.DocumentProto;
 import com.google.android.icing.proto.GetAllNamespacesResultProto;
@@ -609,7 +610,7 @@
         SearchSpecProto searchSpecProto = SearchSpecToProtoConverter.toSearchSpecProto(searchSpec);
         SearchSpecProto.Builder searchSpecBuilder =
                 searchSpecProto.toBuilder().setQuery(queryExpression);
-        DeleteResultProto deleteResultProto;
+        DeleteByQueryResultProto deleteResultProto;
         mReadWriteLock.writeLock().lock();
         try {
             // Only rewrite SearchSpec for non empty prefixes.
@@ -797,11 +798,27 @@
      * Removes any prefixes from types and namespaces mentioned anywhere in {@code documentBuilder}.
      *
      * @param documentBuilder The document to mutate
+     * @return Prefix name that was removed from the document.
+     * @throws AppSearchException if there are unexpected database prefixing errors.
      */
+    @NonNull
     @VisibleForTesting
-    static void removePrefixesFromDocument(@NonNull DocumentProto.Builder documentBuilder)
+    static String removePrefixesFromDocument(@NonNull DocumentProto.Builder documentBuilder)
             throws AppSearchException {
         // Rewrite the type name and namespace to remove the prefix.
+        String schemaPrefix = getPrefix(documentBuilder.getSchema());
+        String namespacePrefix = getPrefix(documentBuilder.getNamespace());
+
+        if (!schemaPrefix.equals(namespacePrefix)) {
+            throw new AppSearchException(
+                    AppSearchResult.RESULT_INTERNAL_ERROR,
+                    "Found unexpected"
+                            + " multiple prefix names in document: "
+                            + schemaPrefix
+                            + ", "
+                            + namespacePrefix);
+        }
+
         documentBuilder.setSchema(removePrefix(documentBuilder.getSchema()));
         documentBuilder.setNamespace(removePrefix(documentBuilder.getNamespace()));
 
@@ -816,12 +833,22 @@
                 for (int documentIdx = 0; documentIdx < documentCount; documentIdx++) {
                     DocumentProto.Builder derivedDocumentBuilder =
                             propertyBuilder.getDocumentValues(documentIdx).toBuilder();
-                    removePrefixesFromDocument(derivedDocumentBuilder);
+                    String nestedPrefix = removePrefixesFromDocument(derivedDocumentBuilder);
+                    if (!nestedPrefix.equals(schemaPrefix)) {
+                        throw new AppSearchException(
+                                AppSearchResult.RESULT_INTERNAL_ERROR,
+                                "Found unexpected multiple prefix names in document: "
+                                        + schemaPrefix
+                                        + ", "
+                                        + nestedPrefix);
+                    }
                     propertyBuilder.setDocumentValues(documentIdx, derivedDocumentBuilder);
                 }
                 documentBuilder.setProperties(propertyIdx, propertyBuilder);
             }
         }
+
+        return schemaPrefix;
     }
 
     /**
@@ -929,6 +956,25 @@
         return packageName + PACKAGE_DELIMITER + databaseName + DATABASE_DELIMITER;
     }
 
+    /**
+     * Returns the package name that's contained within the {@code prefix}.
+     *
+     * @param prefix Prefix string that contains the package name inside of it. The package name
+     *     must be in the front of the string, and separated from the rest of the string by the
+     *     {@link #PACKAGE_DELIMITER}.
+     * @return Valid package name.
+     */
+    @NonNull
+    private static String getPackageName(@NonNull String prefix) {
+        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);
+            return "";
+        }
+        return prefix.substring(0, delimiterIndex);
+    }
+
     @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
@@ -949,7 +995,7 @@
         if (databaseDelimiterIndex == -1) {
             throw new AppSearchException(
                     AppSearchResult.RESULT_UNKNOWN_ERROR,
-                    "The databaseName prefixed value doesn't contains a valid database name.");
+                    "The databaseName prefixed value doesn't contain a valid database name.");
         }
 
         // Add 1 to include the char size of the DATABASE_DELIMITER
@@ -1034,20 +1080,24 @@
     }
 
     /** Remove the rewritten schema types from any result documents. */
-    private static SearchResultPage rewriteSearchResultProto(
-            @NonNull SearchResultProto searchResultProto) throws AppSearchException {
+    @NonNull
+    @VisibleForTesting
+    static SearchResultPage rewriteSearchResultProto(@NonNull SearchResultProto searchResultProto)
+            throws AppSearchException {
+        // Parallel array of package names for each document search result.
+        List<String> packageNames = new ArrayList<>(searchResultProto.getResultsCount());
+
         SearchResultProto.Builder resultsBuilder = searchResultProto.toBuilder();
         for (int i = 0; i < searchResultProto.getResultsCount(); i++) {
-            if (searchResultProto.getResults(i).hasDocument()) {
-                SearchResultProto.ResultProto.Builder resultBuilder =
-                        searchResultProto.getResults(i).toBuilder();
-                DocumentProto.Builder documentBuilder = resultBuilder.getDocument().toBuilder();
-                removePrefixesFromDocument(documentBuilder);
-                resultBuilder.setDocument(documentBuilder);
-                resultsBuilder.setResults(i, resultBuilder);
-            }
+            SearchResultProto.ResultProto.Builder resultBuilder =
+                    searchResultProto.getResults(i).toBuilder();
+            DocumentProto.Builder documentBuilder = resultBuilder.getDocument().toBuilder();
+            String prefix = removePrefixesFromDocument(documentBuilder);
+            packageNames.add(getPackageName(prefix));
+            resultBuilder.setDocument(documentBuilder);
+            resultsBuilder.setResults(i, resultBuilder);
         }
-        return SearchResultToProtoConverter.toSearchResultPage(resultsBuilder);
+        return SearchResultToProtoConverter.toSearchResultPage(resultsBuilder, packageNames);
     }
 
     @GuardedBy("mReadWriteLock")
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverter.java
index 5474cd0..a2386ec 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverter.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverter.java
@@ -54,40 +54,43 @@
         for (int i = 0; i < keys.size(); i++) {
             String name = keys.get(i);
             PropertyProto.Builder propertyProto = PropertyProto.newBuilder().setName(name);
-            String[] stringValues = document.getPropertyStringArray(name);
-            long[] longValues = document.getPropertyLongArray(name);
-            double[] doubleValues = document.getPropertyDoubleArray(name);
-            boolean[] booleanValues = document.getPropertyBooleanArray(name);
-            byte[][] bytesValues = document.getPropertyBytesArray(name);
-            GenericDocument[] documentValues = document.getPropertyDocumentArray(name);
-            if (stringValues != null) {
+            Object property = document.getProperty(name);
+            if (property instanceof String[]) {
+                String[] stringValues = (String[]) property;
                 for (int j = 0; j < stringValues.length; j++) {
                     propertyProto.addStringValues(stringValues[j]);
                 }
-            } else if (longValues != null) {
+            } else if (property instanceof long[]) {
+                long[] longValues = (long[]) property;
                 for (int j = 0; j < longValues.length; j++) {
                     propertyProto.addInt64Values(longValues[j]);
                 }
-            } else if (doubleValues != null) {
+            } else if (property instanceof double[]) {
+                double[] doubleValues = (double[]) property;
                 for (int j = 0; j < doubleValues.length; j++) {
                     propertyProto.addDoubleValues(doubleValues[j]);
                 }
-            } else if (booleanValues != null) {
+            } else if (property instanceof boolean[]) {
+                boolean[] booleanValues = (boolean[]) property;
                 for (int j = 0; j < booleanValues.length; j++) {
                     propertyProto.addBooleanValues(booleanValues[j]);
                 }
-            } else if (bytesValues != null) {
+            } else if (property instanceof byte[][]) {
+                byte[][] bytesValues = (byte[][]) property;
                 for (int j = 0; j < bytesValues.length; j++) {
                     propertyProto.addBytesValues(ByteString.copyFrom(bytesValues[j]));
                 }
-            } else if (documentValues != null) {
+            } else if (property instanceof GenericDocument[]) {
+                GenericDocument[] documentValues = (GenericDocument[]) property;
                 for (int j = 0; j < documentValues.length; j++) {
                     DocumentProto proto = toDocumentProto(documentValues[j]);
                     propertyProto.addDocumentValues(proto);
                 }
             } else {
                 throw new IllegalStateException(
-                        "Property \"" + name + "\" has unsupported value type");
+                        String.format(
+                                "Property \"%s\" has unsupported value type %s",
+                                name, property.getClass().toString()));
             }
             mProtoBuilder.addProperties(propertyProto);
         }
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 4d107a9..ccd567d 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
@@ -22,12 +22,15 @@
 import android.app.appsearch.SearchResultPage;
 import android.os.Bundle;
 
+import com.android.internal.util.Preconditions;
+
 import com.google.android.icing.proto.SearchResultProto;
 import com.google.android.icing.proto.SearchResultProtoOrBuilder;
 import com.google.android.icing.proto.SnippetMatchProto;
 import com.google.android.icing.proto.SnippetProto;
 
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Translates a {@link SearchResultProto} into {@link SearchResult}s.
@@ -37,27 +40,45 @@
 public class SearchResultToProtoConverter {
     private SearchResultToProtoConverter() {}
 
-    /** Translate a {@link SearchResultProto} into {@link SearchResultPage}. */
+    /**
+     * Translate a {@link SearchResultProto} into {@link SearchResultPage}.
+     *
+     * @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).
+     * @return {@link SearchResultPage} of results.
+     */
     @NonNull
-    public static SearchResultPage toSearchResultPage(@NonNull SearchResultProtoOrBuilder proto) {
+    public static SearchResultPage toSearchResultPage(
+            @NonNull SearchResultProtoOrBuilder proto, @NonNull List<String> packageNames) {
+        Preconditions.checkArgument(
+                proto.getResultsCount() == packageNames.size(),
+                "Size of " + "results does not match the number of package names.");
         Bundle bundle = new Bundle();
         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)));
+            resultBundles.add(toSearchResultBundle(proto.getResults(i), packageNames.get(i)));
         }
         bundle.putParcelableArrayList(SearchResultPage.RESULTS_FIELD, resultBundles);
         return new SearchResultPage(bundle);
     }
 
-    /** Translate a {@link SearchResultProto.ResultProto} into {@link SearchResult}. */
+    /**
+     * Translate a {@link SearchResultProto.ResultProto} into {@link SearchResult}.
+     *
+     * @param proto The proto to be converted.
+     * @param packageName The package name associated with the document in {@code proto}.
+     * @return A {@link SearchResult} bundle.
+     */
     @NonNull
     private static Bundle toSearchResultBundle(
-            @NonNull SearchResultProto.ResultProtoOrBuilder proto) {
+            @NonNull SearchResultProto.ResultProtoOrBuilder proto, @NonNull String packageName) {
         Bundle bundle = new Bundle();
         GenericDocument document =
                 GenericDocumentToProtoConverter.toGenericDocument(proto.getDocument());
         bundle.putBundle(SearchResult.DOCUMENT_FIELD, document.getBundle());
+        bundle.putString(SearchResult.PACKAGE_NAME_FIELD, packageName);
 
         ArrayList<Bundle> matchList = new ArrayList<>();
         if (proto.hasSnippet()) {
diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt
index 2b1ec08..73f64dc 100644
--- a/apex/appsearch/synced_jetpack_changeid.txt
+++ b/apex/appsearch/synced_jetpack_changeid.txt
@@ -1 +1 @@
-I596ad1269b4d3a4f26db67f5d970aeaa3bf94a9d
+I8b7425b3f87153547d1c8f5b560be5a54c9be97e
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 9e22bf6..6859747 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
@@ -46,7 +46,7 @@
     private final ExecutorService mExecutor;
 
     @NonNull
-    public static ListenableFuture<GlobalSearchSessionShimImpl> createGlobalSearchSession() {
+    public static ListenableFuture<GlobalSearchSessionShim> createGlobalSearchSession() {
         Context context = ApplicationProvider.getApplicationContext();
         AppSearchManager appSearchManager = context.getSystemService(AppSearchManager.class);
         SettableFuture<AppSearchResult<GlobalSearchSession>> future = SettableFuture.create();
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 8383df4..e439c5a 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright 2020 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.app.appsearch;
 
 import android.annotation.NonNull;
@@ -26,7 +27,7 @@
  * Represents a connection to an AppSearch storage system where {@link GenericDocument}s can be
  * placed and queried.
  *
- * All implementations of this interface must be thread safe.
+ * <p>All implementations of this interface must be thread safe.
  */
 public interface AppSearchSessionShim {
 
@@ -37,41 +38,42 @@
      * to {@link #setSchema}, if any, to determine how to treat existing documents. The following
      * types of schema modifications are always safe and are made without deleting any existing
      * documents:
+     *
      * <ul>
-     *     <li>Addition of new types
-     *     <li>Addition of new
-     *         {@link AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} or
-     *         {@link AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED REPEATED} properties to a
-     *         type
-     *     <li>Changing the cardinality of a data type to be less restrictive (e.g. changing an
-     *         {@link AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} property into a
-     *         {@link AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED REPEATED} property.
+     *   <li>Addition of new types
+     *   <li>Addition of new {@link AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} or
+     *       {@link AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED REPEATED} properties to a
+     *       type
+     *   <li>Changing the cardinality of a data type to be less restrictive (e.g. changing an {@link
+     *       AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} property into a {@link
+     *       AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED REPEATED} property.
      * </ul>
      *
      * <p>The following types of schema changes are not backwards-compatible:
+     *
      * <ul>
-     *     <li>Removal of an existing type
-     *     <li>Removal of a property from a type
-     *     <li>Changing the data type ({@code boolean}, {@code long}, etc.) of an existing property
-     *     <li>For properties of {@code Document} type, changing the schema type of
-     *         {@code Document}s of that property
-     *     <li>Changing the cardinality of a data type to be more restrictive (e.g. changing an
-     *         {@link AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} property into a
-     *         {@link AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED REQUIRED} property).
-     *     <li>Adding a
-     *         {@link AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED REQUIRED} property.
+     *   <li>Removal of an existing type
+     *   <li>Removal of a property from a type
+     *   <li>Changing the data type ({@code boolean}, {@code long}, etc.) of an existing property
+     *   <li>For properties of {@code Document} type, changing the schema type of {@code Document}s
+     *       of that property
+     *   <li>Changing the cardinality of a data type to be more restrictive (e.g. changing an {@link
+     *       AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} property into a {@link
+     *       AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED REQUIRED} property).
+     *   <li>Adding a {@link AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED REQUIRED} property.
      * </ul>
+     *
      * <p>Supplying a schema with such changes will, by default, result in this call completing its
-     * future with an {@link androidx.appsearch.exceptions.AppSearchException} with a code of
+     * future with an {@link android.app.appsearch.exceptions.AppSearchException} with a code of
      * {@link AppSearchResult#RESULT_INVALID_SCHEMA} and a message describing the incompatibility.
      * In this case the previously set schema will remain active.
      *
      * <p>If you need to make non-backwards-compatible changes as described above, you can set the
      * {@link SetSchemaRequest.Builder#setForceOverride} method to {@code true}. In this case,
-     * instead of completing its future with an
-     * {@link androidx.appsearch.exceptions.AppSearchException} with the
-     * {@link AppSearchResult#RESULT_INVALID_SCHEMA} error code, all documents which are not
-     * compatible with the new schema will be deleted and the incompatible schema will be applied.
+     * instead of completing its future with an {@link
+     * android.app.appsearch.exceptions.AppSearchException} with the {@link
+     * AppSearchResult#RESULT_INVALID_SCHEMA} error code, all documents which are not compatible
+     * with the new schema will be deleted and the incompatible schema will be applied.
      *
      * <p>It is a no-op to set the same schema as has been previously set; this is handled
      * efficiently.
@@ -79,8 +81,8 @@
      * <p>By default, documents are visible on platform surfaces. To opt out, call {@code
      * SetSchemaRequest.Builder#setPlatformSurfaceable} with {@code surfaceable} as false. Any
      * visibility settings apply only to the schemas that are included in the {@code request}.
-     * Visibility settings for a schema type do not apply or persist across
-     * {@link SetSchemaRequest}s.
+     * Visibility settings for a schema type do not apply or persist across {@link
+     * SetSchemaRequest}s.
      *
      * @param request The schema update request.
      * @return The pending result of performing this operation.
@@ -107,10 +109,9 @@
      * schema type previously registered via the {@link #setSchema} method.
      *
      * @param request {@link PutDocumentsRequest} containing documents to be indexed
-     * @return The pending result of performing this operation. The keys of the returned
-     * {@link AppSearchBatchResult} are the URIs of the input documents. The values are
-     * {@code null} if they were successfully indexed, or a failed {@link AppSearchResult}
-     * otherwise.
+     * @return The pending result of performing this operation. The keys of the returned {@link
+     *     AppSearchBatchResult} are the URIs of the input documents. The values are {@code null} if
+     *     they were successfully indexed, or a failed {@link AppSearchResult} otherwise.
      */
     @NonNull
     ListenableFuture<AppSearchBatchResult<String, Void>> putDocuments(
@@ -120,11 +121,11 @@
      * Retrieves {@link GenericDocument}s by URI.
      *
      * @param request {@link GetByUriRequest} containing URIs to be retrieved.
-     * @return The pending result of performing this operation. The keys of the returned
-     * {@link AppSearchBatchResult} are the input URIs. The values are the returned
-     * {@link GenericDocument}s on success, or a failed {@link AppSearchResult} otherwise.
-     * URIs that are not found will return a failed {@link AppSearchResult} with a result code
-     * of {@link AppSearchResult#RESULT_NOT_FOUND}.
+     * @return The pending result of performing this operation. The keys of the returned {@link
+     *     AppSearchBatchResult} are the input URIs. The values are the returned {@link
+     *     GenericDocument}s on success, or a failed {@link AppSearchResult} otherwise. URIs that
+     *     are not found will return a failed {@link AppSearchResult} with a result code of {@link
+     *     AppSearchResult#RESULT_NOT_FOUND}.
      */
     @NonNull
     ListenableFuture<AppSearchBatchResult<String, GenericDocument>> getByUri(
@@ -134,42 +135,39 @@
      * Searches a document based on a given query string.
      *
      * <p>Currently we support following features in the raw query format:
+     *
      * <ul>
-     *     <li>AND
-     *     <p>AND joins (e.g. “match documents that have both the terms ‘dog’ and
-     *     ‘cat’”).
-     *     Example: hello world matches documents that have both ‘hello’ and ‘world’
-     *     <li>OR
-     *     <p>OR joins (e.g. “match documents that have either the term ‘dog’ or
-     *     ‘cat’”).
-     *     Example: dog OR puppy
-     *     <li>Exclusion
-     *     <p>Exclude a term (e.g. “match documents that do
-     *     not have the term ‘dog’”).
-     *     Example: -dog excludes the term ‘dog’
-     *     <li>Grouping terms
-     *     <p>Allow for conceptual grouping of subqueries to enable hierarchical structures (e.g.
-     *     “match documents that have either ‘dog’ or ‘puppy’, and either ‘cat’ or ‘kitten’”).
-     *     Example: (dog puppy) (cat kitten) two one group containing two terms.
-     *     <li>Property restricts
-     *     <p> Specifies which properties of a document to specifically match terms in (e.g.
-     *     “match documents where the ‘subject’ property contains ‘important’”).
-     *     Example: subject:important matches documents with the term ‘important’ in the
-     *     ‘subject’ property
-     *     <li>Schema type restricts
-     *     <p>This is similar to property restricts, but allows for restricts on top-level document
-     *     fields, such as schema_type. Clients should be able to limit their query to documents of
-     *     a certain schema_type (e.g. “match documents that are of the ‘Email’ schema_type”).
-     *     Example: { schema_type_filters: “Email”, “Video”,query: “dog” } will match documents
-     *     that contain the query term ‘dog’ and are of either the ‘Email’ schema type or the
-     *     ‘Video’ schema type.
+     *   <li>AND
+     *       <p>AND joins (e.g. “match documents that have both the terms ‘dog’ and ‘cat’”).
+     *       Example: hello world matches documents that have both ‘hello’ and ‘world’
+     *   <li>OR
+     *       <p>OR joins (e.g. “match documents that have either the term ‘dog’ or ‘cat’”). Example:
+     *       dog OR puppy
+     *   <li>Exclusion
+     *       <p>Exclude a term (e.g. “match documents that do not have the term ‘dog’”). Example:
+     *       -dog excludes the term ‘dog’
+     *   <li>Grouping terms
+     *       <p>Allow for conceptual grouping of subqueries to enable hierarchical structures (e.g.
+     *       “match documents that have either ‘dog’ or ‘puppy’, and either ‘cat’ or ‘kitten’”).
+     *       Example: (dog puppy) (cat kitten) two one group containing two terms.
+     *   <li>Property restricts
+     *       <p>Specifies which properties of a document to specifically match terms in (e.g. “match
+     *       documents where the ‘subject’ property contains ‘important’”). Example:
+     *       subject:important matches documents with the term ‘important’ in the ‘subject’ property
+     *   <li>Schema type restricts
+     *       <p>This is similar to property restricts, but allows for restricts on top-level
+     *       document fields, such as schema_type. Clients should be able to limit their query to
+     *       documents of a certain schema_type (e.g. “match documents that are of the ‘Email’
+     *       schema_type”). Example: { schema_type_filters: “Email”, “Video”,query: “dog” } will
+     *       match documents that contain the query term ‘dog’ and are of either the ‘Email’ schema
+     *       type or the ‘Video’ schema type.
      * </ul>
      *
-     * <p> This method is lightweight. The heavy work will be done in
-     * {@link SearchResults#getNextPage()}.
+     * <p>This method is lightweight. The heavy work will be done in {@link
+     * SearchResultsShim#getNextPage()}.
      *
      * @param queryExpression Query String to search.
-     * @param searchSpec      Spec for setting filters, raw query etc.
+     * @param searchSpec Spec for setting filters, raw query etc.
      * @return The search result of performing this operation.
      */
     @NonNull
@@ -179,11 +177,10 @@
      * Removes {@link GenericDocument}s from the index by URI.
      *
      * @param request Request containing URIs to be removed.
-     * @return The pending result of performing this operation. The keys of the returned
-     * {@link AppSearchBatchResult} are the input URIs. The values are {@code null} on success,
-     * or a failed {@link AppSearchResult} otherwise. URIs that are not found will return a
-     * failed {@link AppSearchResult} with a result code of
-     * {@link AppSearchResult#RESULT_NOT_FOUND}.
+     * @return The pending result of performing this operation. The keys of the returned {@link
+     *     AppSearchBatchResult} are the input URIs. The values are {@code null} on success, or a
+     *     failed {@link AppSearchResult} otherwise. URIs that are not found will return a failed
+     *     {@link AppSearchResult} with a result code of {@link AppSearchResult#RESULT_NOT_FOUND}.
      */
     @NonNull
     ListenableFuture<AppSearchBatchResult<String, Void>> removeByUri(
@@ -191,18 +188,18 @@
 
     /**
      * Removes {@link GenericDocument}s from the index by Query. Documents will be removed if they
-     * match the {@code queryExpression} in given namespaces and schemaTypes which is set via
-     * {@link SearchSpec.Builder#addNamespace} and {@link SearchSpec.Builder#addSchemaType}.
+     * match the {@code queryExpression} in given namespaces and schemaTypes which is set via {@link
+     * SearchSpec.Builder#addNamespace} and {@link SearchSpec.Builder#addSchemaType}.
      *
-     * <p> An empty {@code queryExpression} matches all documents.
+     * <p>An empty {@code queryExpression} matches all documents.
      *
-     * <p> An empty set of namespaces or schemaTypes matches all namespaces or schemaTypes in
-     * the current database.
+     * <p>An empty set of namespaces or schemaTypes matches all namespaces or schemaTypes in the
+     * current database.
      *
      * @param queryExpression Query String to search.
-     * @param searchSpec      Spec containing schemaTypes, namespaces and query expression
-     *                        indicates how document will be removed. All specific about how to
-     *                        scoring, ordering, snippeting and resulting will be ignored.
+     * @param searchSpec Spec containing schemaTypes, namespaces and query expression indicates how
+     *     document will be removed. All specific about how to scoring, ordering, snippeting and
+     *     resulting will be ignored.
      * @return The pending result of performing this operation.
      */
     @NonNull
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 33dc379..2d09247 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright 2020 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.app.appsearch;
 
 import android.annotation.NonNull;
@@ -27,42 +28,39 @@
      * Searches across all documents in the storage based on a given query string.
      *
      * <p>Currently we support following features in the raw query format:
+     *
      * <ul>
-     *     <li>AND
-     *     <p>AND joins (e.g. “match documents that have both the terms ‘dog’ and
-     *     ‘cat’”).
-     *     Example: hello world matches documents that have both ‘hello’ and ‘world’
-     *     <li>OR
-     *     <p>OR joins (e.g. “match documents that have either the term ‘dog’ or
-     *     ‘cat’”).
-     *     Example: dog OR puppy
-     *     <li>Exclusion
-     *     <p>Exclude a term (e.g. “match documents that do
-     *     not have the term ‘dog’”).
-     *     Example: -dog excludes the term ‘dog’
-     *     <li>Grouping terms
-     *     <p>Allow for conceptual grouping of subqueries to enable hierarchical structures (e.g.
-     *     “match documents that have either ‘dog’ or ‘puppy’, and either ‘cat’ or ‘kitten’”).
-     *     Example: (dog puppy) (cat kitten) two one group containing two terms.
-     *     <li>Property restricts
-     *     <p> Specifies which properties of a document to specifically match terms in (e.g.
-     *     “match documents where the ‘subject’ property contains ‘important’”).
-     *     Example: subject:important matches documents with the term ‘important’ in the
-     *     ‘subject’ property
-     *     <li>Schema type restricts
-     *     <p>This is similar to property restricts, but allows for restricts on top-level document
-     *     fields, such as schema_type. Clients should be able to limit their query to documents of
-     *     a certain schema_type (e.g. “match documents that are of the ‘Email’ schema_type”).
-     *     Example: { schema_type_filters: “Email”, “Video”,query: “dog” } will match documents
-     *     that contain the query term ‘dog’ and are of either the ‘Email’ schema type or the
-     *     ‘Video’ schema type.
+     *   <li>AND
+     *       <p>AND joins (e.g. “match documents that have both the terms ‘dog’ and ‘cat’”).
+     *       Example: hello world matches documents that have both ‘hello’ and ‘world’
+     *   <li>OR
+     *       <p>OR joins (e.g. “match documents that have either the term ‘dog’ or ‘cat’”). Example:
+     *       dog OR puppy
+     *   <li>Exclusion
+     *       <p>Exclude a term (e.g. “match documents that do not have the term ‘dog’”). Example:
+     *       -dog excludes the term ‘dog’
+     *   <li>Grouping terms
+     *       <p>Allow for conceptual grouping of subqueries to enable hierarchical structures (e.g.
+     *       “match documents that have either ‘dog’ or ‘puppy’, and either ‘cat’ or ‘kitten’”).
+     *       Example: (dog puppy) (cat kitten) two one group containing two terms.
+     *   <li>Property restricts
+     *       <p>Specifies which properties of a document to specifically match terms in (e.g. “match
+     *       documents where the ‘subject’ property contains ‘important’”). Example:
+     *       subject:important matches documents with the term ‘important’ in the ‘subject’ property
+     *   <li>Schema type restricts
+     *       <p>This is similar to property restricts, but allows for restricts on top-level
+     *       document fields, such as schema_type. Clients should be able to limit their query to
+     *       documents of a certain schema_type (e.g. “match documents that are of the ‘Email’
+     *       schema_type”). Example: { schema_type_filters: “Email”, “Video”,query: “dog” } will
+     *       match documents that contain the query term ‘dog’ and are of either the ‘Email’ schema
+     *       type or the ‘Video’ schema type.
      * </ul>
      *
-     * <p> This method is lightweight. The heavy work will be done in
-     * {@link SearchResults#getNextPage}.
+     * <p>This method is lightweight. The heavy work will be done in {@link
+     * SearchResultsShim#getNextPage()}.
      *
      * @param queryExpression Query String to search.
-     * @param searchSpec      Spec for setting filters, raw query etc.
+     * @param searchSpec Spec for setting filters, raw query etc.
      * @return The search result of performing this operation.
      */
     @NonNull
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/SearchResultsShim.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/SearchResultsShim.java
index f387a17..328c65c 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/SearchResultsShim.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/SearchResultsShim.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright 2020 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.app.appsearch;
 
 import android.annotation.NonNull;
@@ -23,10 +24,10 @@
 import java.util.List;
 
 /**
- * SearchResults are a returned object from a query API.
+ * SearchResultsShim are a returned object from a query API.
  *
- * <p>Each {@link SearchResult} contains a document and may contain other fields like snippets
- * based on request.
+ * <p>Each {@link SearchResult} contains a document and may contain other fields like snippets based
+ * on request.
  *
  * <p>Should close this object after finish fetching results.
  *
@@ -36,11 +37,10 @@
     /**
      * Gets a whole page of {@link SearchResult}s.
      *
-     * <p>Re-call this method to get next page of {@link SearchResult}, until it returns an
-     * empty list.
+     * <p>Re-call this method to get next page of {@link SearchResult}, until it returns an empty
+     * list.
      *
-     * <p>The page size is set by
-     * {@link android.app.appsearch.SearchSpec.Builder#setResultCountPerPage}.
+     * <p>The page size is set by {@link SearchSpec.Builder#setResultCountPerPage}.
      *
      * @return The pending result of performing this operation.
      */
diff --git a/core/api/current.txt b/core/api/current.txt
index 2ce0b35..b6a1534 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -6925,6 +6925,7 @@
     method @NonNull public java.util.List<java.lang.String> getDelegatedScopes(@Nullable android.content.ComponentName, @NonNull String);
     method public CharSequence getDeviceOwnerLockScreenInfo();
     method public CharSequence getEndUserSessionMessage(@NonNull android.content.ComponentName);
+    method @NonNull public String getEnrollmentSpecificId();
     method @Nullable public android.app.admin.FactoryResetProtectionPolicy getFactoryResetProtectionPolicy(@Nullable android.content.ComponentName);
     method @Nullable public String getGlobalPrivateDnsHost(@NonNull android.content.ComponentName);
     method public int getGlobalPrivateDnsMode(@NonNull android.content.ComponentName);
@@ -7075,6 +7076,7 @@
     method @NonNull public java.util.List<java.lang.String> setMeteredDataDisabledPackages(@NonNull android.content.ComponentName, @NonNull java.util.List<java.lang.String>);
     method public void setNetworkLoggingEnabled(@Nullable android.content.ComponentName, boolean);
     method @Deprecated public void setOrganizationColor(@NonNull android.content.ComponentName, int);
+    method public void setOrganizationId(@NonNull String);
     method public void setOrganizationName(@NonNull android.content.ComponentName, @Nullable CharSequence);
     method public void setOverrideApnsEnabled(@NonNull android.content.ComponentName, boolean);
     method @NonNull public String[] setPackagesSuspended(@NonNull android.content.ComponentName, @NonNull String[], boolean);
@@ -7135,7 +7137,7 @@
     field public static final String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
     field public static final String ACTION_PROFILE_OWNER_CHANGED = "android.app.action.PROFILE_OWNER_CHANGED";
     field public static final String ACTION_PROVISIONING_SUCCESSFUL = "android.app.action.PROVISIONING_SUCCESSFUL";
-    field public static final String ACTION_PROVISION_MANAGED_DEVICE = "android.app.action.PROVISION_MANAGED_DEVICE";
+    field @Deprecated public static final String ACTION_PROVISION_MANAGED_DEVICE = "android.app.action.PROVISION_MANAGED_DEVICE";
     field public static final String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.PROVISION_MANAGED_PROFILE";
     field public static final String ACTION_SET_NEW_PARENT_PROFILE_PASSWORD = "android.app.action.SET_NEW_PARENT_PROFILE_PASSWORD";
     field public static final String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD";
@@ -7186,7 +7188,7 @@
     field public static final String EXTRA_PROVISIONING_SERIAL_NUMBER = "android.app.extra.PROVISIONING_SERIAL_NUMBER";
     field public static final String EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS = "android.app.extra.PROVISIONING_SKIP_EDUCATION_SCREENS";
     field public static final String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
-    field public static final String EXTRA_PROVISIONING_SKIP_USER_CONSENT = "android.app.extra.PROVISIONING_SKIP_USER_CONSENT";
+    field @Deprecated public static final String EXTRA_PROVISIONING_SKIP_USER_CONSENT = "android.app.extra.PROVISIONING_SKIP_USER_CONSENT";
     field public static final String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE";
     field public static final String EXTRA_PROVISIONING_WIFI_ANONYMOUS_IDENTITY = "android.app.extra.PROVISIONING_WIFI_ANONYMOUS_IDENTITY";
     field public static final String EXTRA_PROVISIONING_WIFI_CA_CERTIFICATE = "android.app.extra.PROVISIONING_WIFI_CA_CERTIFICATE";
@@ -7492,6 +7494,7 @@
     method public int getMaxTextEms();
     method public int getMaxTextLength();
     method public int getMinTextEms();
+    method @Nullable public String[] getOnReceiveContentMimeTypes();
     method public int getScrollX();
     method public int getScrollY();
     method @Nullable public CharSequence getText();
@@ -7826,6 +7829,52 @@
 
 }
 
+package android.app.people {
+
+  public final class ConversationStatus implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getActivity();
+    method public int getAvailability();
+    method @Nullable public CharSequence getDescription();
+    method public long getEndTimeMillis();
+    method @Nullable public android.graphics.drawable.Icon getIcon();
+    method @NonNull public String getId();
+    method public long getStartTimeMillis();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int ACTIVITY_ANNIVERSARY = 2; // 0x2
+    field public static final int ACTIVITY_BIRTHDAY = 1; // 0x1
+    field public static final int ACTIVITY_GAME = 5; // 0x5
+    field public static final int ACTIVITY_LOCATION = 6; // 0x6
+    field public static final int ACTIVITY_MEDIA = 4; // 0x4
+    field public static final int ACTIVITY_NEW_STORY = 3; // 0x3
+    field public static final int ACTIVITY_OTHER = 0; // 0x0
+    field public static final int ACTIVITY_UPCOMING_BIRTHDAY = 7; // 0x7
+    field public static final int AVAILABILITY_AVAILABLE = 0; // 0x0
+    field public static final int AVAILABILITY_BUSY = 1; // 0x1
+    field public static final int AVAILABILITY_OFFLINE = 2; // 0x2
+    field public static final int AVAILABILITY_UNKNOWN = -1; // 0xffffffff
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.people.ConversationStatus> CREATOR;
+  }
+
+  public static final class ConversationStatus.Builder {
+    ctor public ConversationStatus.Builder(@NonNull String, @NonNull int);
+    method @NonNull public android.app.people.ConversationStatus build();
+    method @NonNull public android.app.people.ConversationStatus.Builder setAvailability(int);
+    method @NonNull public android.app.people.ConversationStatus.Builder setDescription(@Nullable CharSequence);
+    method @NonNull public android.app.people.ConversationStatus.Builder setEndTimeMillis(long);
+    method @NonNull public android.app.people.ConversationStatus.Builder setIcon(@Nullable android.graphics.drawable.Icon);
+    method @NonNull public android.app.people.ConversationStatus.Builder setStartTimeMillis(long);
+  }
+
+  public final class PeopleManager {
+    method public void addOrUpdateStatus(@NonNull String, @NonNull android.app.people.ConversationStatus);
+    method public void clearStatus(@NonNull String, @NonNull String);
+    method public void clearStatuses(@NonNull String);
+    method @NonNull public java.util.List<android.app.people.ConversationStatus> getStatuses(@NonNull String);
+  }
+
+}
+
 package android.app.role {
 
   public final class RoleManager {
@@ -10315,6 +10364,7 @@
     field public static final String NFC_SERVICE = "nfc";
     field public static final String NOTIFICATION_SERVICE = "notification";
     field public static final String NSD_SERVICE = "servicediscovery";
+    field public static final String PEOPLE_SERVICE = "people";
     field public static final String POWER_SERVICE = "power";
     field public static final String PRINT_SERVICE = "print";
     field public static final int RECEIVER_VISIBLE_TO_INSTANT_APPS = 1; // 0x1
@@ -12327,6 +12377,7 @@
     field public static final String FEATURE_TOUCHSCREEN_MULTITOUCH = "android.hardware.touchscreen.multitouch";
     field public static final String FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT = "android.hardware.touchscreen.multitouch.distinct";
     field public static final String FEATURE_TOUCHSCREEN_MULTITOUCH_JAZZHAND = "android.hardware.touchscreen.multitouch.jazzhand";
+    field public static final String FEATURE_TRANSLATION = "android.software.translation";
     field public static final String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory";
     field public static final String FEATURE_USB_HOST = "android.hardware.usb.host";
     field public static final String FEATURE_VERIFIED_BOOT = "android.software.verified_boot";
@@ -31384,6 +31435,7 @@
     method @NonNull public android.os.VibrationEffect.Composition addPrimitive(int, @FloatRange(from=0.0f, to=1.0f) float, @IntRange(from=0) int);
     method @NonNull public android.os.VibrationEffect compose();
     field public static final int PRIMITIVE_CLICK = 1; // 0x1
+    field public static final int PRIMITIVE_LOW_TICK = 8; // 0x8
     field public static final int PRIMITIVE_QUICK_FALL = 6; // 0x6
     field public static final int PRIMITIVE_QUICK_RISE = 4; // 0x4
     field public static final int PRIMITIVE_SLOW_RISE = 5; // 0x5
@@ -48717,6 +48769,7 @@
     method public void setMaxTextEms(int);
     method public void setMaxTextLength(int);
     method public void setMinTextEms(int);
+    method public void setOnReceiveContentMimeTypes(@Nullable String[]);
     method public abstract void setOpaque(boolean);
     method public abstract void setSelected(boolean);
     method public abstract void setText(CharSequence);
@@ -51559,6 +51612,66 @@
 
 }
 
+package android.view.translation {
+
+  public final class TranslationManager {
+    method @Nullable @WorkerThread public android.view.translation.Translator createTranslator(@NonNull android.view.translation.TranslationSpec, @NonNull android.view.translation.TranslationSpec);
+    method @NonNull @WorkerThread public java.util.List<java.lang.String> getSupportedLocales();
+  }
+
+  public final class TranslationRequest implements android.os.Parcelable {
+    ctor public TranslationRequest(@Nullable CharSequence);
+    method public int describeContents();
+    method @Nullable public android.view.autofill.AutofillId getAutofillId();
+    method @Nullable public CharSequence getTranslationText();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.view.translation.TranslationRequest> CREATOR;
+  }
+
+  public static final class TranslationRequest.Builder {
+    ctor public TranslationRequest.Builder();
+    method @NonNull public android.view.translation.TranslationRequest build();
+    method @NonNull public android.view.translation.TranslationRequest.Builder setAutofillId(@NonNull android.view.autofill.AutofillId);
+    method @NonNull public android.view.translation.TranslationRequest.Builder setTranslationText(@NonNull CharSequence);
+  }
+
+  public final class TranslationResponse implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getTranslationStatus();
+    method @NonNull public java.util.List<android.view.translation.TranslationRequest> getTranslations();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.view.translation.TranslationResponse> CREATOR;
+    field public static final int TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE = 2; // 0x2
+    field public static final int TRANSLATION_STATUS_SUCCESS = 0; // 0x0
+    field public static final int TRANSLATION_STATUS_UNKNOWN_ERROR = 1; // 0x1
+  }
+
+  public static final class TranslationResponse.Builder {
+    ctor public TranslationResponse.Builder(int);
+    method @NonNull public android.view.translation.TranslationResponse.Builder addTranslations(@NonNull android.view.translation.TranslationRequest);
+    method @NonNull public android.view.translation.TranslationResponse build();
+    method @NonNull public android.view.translation.TranslationResponse.Builder setTranslationStatus(int);
+    method @NonNull public android.view.translation.TranslationResponse.Builder setTranslations(@NonNull java.util.List<android.view.translation.TranslationRequest>);
+  }
+
+  public final class TranslationSpec implements android.os.Parcelable {
+    ctor public TranslationSpec(@NonNull String, int);
+    method public int describeContents();
+    method public int getDataFormat();
+    method @NonNull public String getLanguage();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.view.translation.TranslationSpec> CREATOR;
+    field public static final int DATA_FORMAT_TEXT = 1; // 0x1
+  }
+
+  public class Translator {
+    method public void destroy();
+    method public boolean isDestroyed();
+    method @Nullable @WorkerThread public android.view.translation.TranslationResponse translate(@NonNull android.view.translation.TranslationRequest);
+  }
+
+}
+
 package android.webkit {
 
   public abstract class ClientCertRequest {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 9a15e77..da79b67 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -52,6 +52,7 @@
     field public static final String BIND_TELEPHONY_NETWORK_SERVICE = "android.permission.BIND_TELEPHONY_NETWORK_SERVICE";
     field public static final String BIND_TEXTCLASSIFIER_SERVICE = "android.permission.BIND_TEXTCLASSIFIER_SERVICE";
     field public static final String BIND_TIME_ZONE_PROVIDER_SERVICE = "android.permission.BIND_TIME_ZONE_PROVIDER_SERVICE";
+    field public static final String BIND_TRANSLATION_SERVICE = "android.permission.BIND_TRANSLATION_SERVICE";
     field public static final String BIND_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT";
     field public static final String BIND_TV_REMOTE_SERVICE = "android.permission.BIND_TV_REMOTE_SERVICE";
     field public static final String BRICK = "android.permission.BRICK";
@@ -906,6 +907,7 @@
     field public static final int STATE_USER_SETUP_FINALIZED = 3; // 0x3
     field public static final int STATE_USER_SETUP_INCOMPLETE = 1; // 0x1
     field public static final int STATE_USER_UNMANAGED = 0; // 0x0
+    field public static final int SUPPORTED_MODES_DEVICE_OWNER = 4; // 0x4
     field public static final int SUPPORTED_MODES_ORGANIZATION_AND_PERSONALLY_OWNED = 3; // 0x3
     field public static final int SUPPORTED_MODES_ORGANIZATION_OWNED = 1; // 0x1
     field public static final int SUPPORTED_MODES_PERSONALLY_OWNED = 2; // 0x2
@@ -1370,8 +1372,6 @@
     method @NonNull @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public java.util.List<java.lang.String> getHeldRolesFromController(@NonNull String);
     method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHolders(@NonNull String);
     method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle);
-    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>);
     method @RequiresPermission(android.Manifest.permission.OBSERVE_ROLE_HOLDERS) public void removeOnRoleHoldersChangedListenerAsUser(@NonNull android.app.role.OnRoleHoldersChangedListener, @NonNull android.os.UserHandle);
     method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void removeRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean removeRoleHolderFromController(@NonNull String, @NonNull String);
@@ -1942,6 +1942,7 @@
     field public static final String SYSTEM_CONFIG_SERVICE = "system_config";
     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 VR_SERVICE = "vrmanager";
     field public static final String WIFI_NL80211_SERVICE = "wifinl80211";
     field @Deprecated public static final String WIFI_RTT_SERVICE = "rttmanager";
@@ -8618,6 +8619,7 @@
     field public static final String NAMESPACE_ACTIVITY_MANAGER = "activity_manager";
     field public static final String NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT = "activity_manager_native_boot";
     field public static final String NAMESPACE_APP_COMPAT = "app_compat";
+    field public static final String NAMESPACE_APP_HIBERNATION = "app_hibernation";
     field public static final String NAMESPACE_ATTENTION_MANAGER_SERVICE = "attention_manager_service";
     field public static final String NAMESPACE_AUTOFILL = "autofill";
     field public static final String NAMESPACE_BATTERY_SAVER = "battery_saver";
@@ -9854,6 +9856,48 @@
 
 }
 
+package android.service.translation {
+
+  public final class TranslationRequest implements android.os.Parcelable {
+    ctor public TranslationRequest(int, @NonNull android.view.translation.TranslationSpec, @NonNull android.view.translation.TranslationSpec, @NonNull java.util.List<android.view.translation.TranslationRequest>);
+    method public int describeContents();
+    method @NonNull public android.view.translation.TranslationSpec getDestSpec();
+    method public int getRequestId();
+    method @NonNull public android.view.translation.TranslationSpec getSourceSpec();
+    method @NonNull public java.util.List<android.view.translation.TranslationRequest> getTranslationRequests();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.service.translation.TranslationRequest> CREATOR;
+  }
+
+  public static final class TranslationRequest.Builder {
+    ctor public TranslationRequest.Builder(int, @NonNull android.view.translation.TranslationSpec, @NonNull android.view.translation.TranslationSpec, @NonNull java.util.List<android.view.translation.TranslationRequest>);
+    method @NonNull public android.service.translation.TranslationRequest.Builder addTranslationRequests(@NonNull android.view.translation.TranslationRequest);
+    method @NonNull public android.service.translation.TranslationRequest build();
+    method @NonNull public android.service.translation.TranslationRequest.Builder setDestSpec(@NonNull android.view.translation.TranslationSpec);
+    method @NonNull public android.service.translation.TranslationRequest.Builder setRequestId(int);
+    method @NonNull public android.service.translation.TranslationRequest.Builder setSourceSpec(@NonNull android.view.translation.TranslationSpec);
+    method @NonNull public android.service.translation.TranslationRequest.Builder setTranslationRequests(@NonNull java.util.List<android.view.translation.TranslationRequest>);
+  }
+
+  public abstract class TranslationService extends android.app.Service {
+    ctor public TranslationService();
+    method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
+    method public void onConnected();
+    method public abstract void onCreateTranslationSession(@NonNull android.view.translation.TranslationSpec, @NonNull android.view.translation.TranslationSpec, int);
+    method public void onDisconnected();
+    method public abstract void onFinishTranslationSession(int);
+    method public abstract void onTranslationRequest(@NonNull android.service.translation.TranslationRequest, int, @NonNull android.os.CancellationSignal, @NonNull android.service.translation.TranslationService.OnTranslationResultCallback);
+    field public static final String SERVICE_INTERFACE = "android.service.translation.TranslationService";
+    field public static final String SERVICE_META_DATA = "android.translation_service";
+  }
+
+  public static interface TranslationService.OnTranslationResultCallback {
+    method public void onError();
+    method public void onTranslationSuccess(@NonNull android.view.translation.TranslationResponse);
+  }
+
+}
+
 package android.service.trust {
 
   public class TrustAgentService extends android.app.Service {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index f0a0297..c03461a 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -18,6 +18,7 @@
     field public static final String MANAGE_CRATES = "android.permission.MANAGE_CRATES";
     field public static final String MANAGE_NOTIFICATION_LISTENERS = "android.permission.MANAGE_NOTIFICATION_LISTENERS";
     field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
+    field public static final String MANAGE_TOAST_RATE_LIMITING = "android.permission.MANAGE_TOAST_RATE_LIMITING";
     field public static final String MODIFY_REFRESH_RATE_SWITCHING_TYPE = "android.permission.MODIFY_REFRESH_RATE_SWITCHING_TYPE";
     field public static final String NETWORK_SETTINGS = "android.permission.NETWORK_SETTINGS";
     field public static final String NETWORK_STACK = "android.permission.NETWORK_STACK";
@@ -274,6 +275,7 @@
     method public boolean isNotificationPolicyAccessGrantedForPackage(@NonNull String);
     method public boolean matchesCallFilter(android.os.Bundle);
     method @RequiresPermission(android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS) public void setNotificationListenerAccessGranted(@NonNull android.content.ComponentName, boolean, boolean);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_TOAST_RATE_LIMITING) public void setToastRateLimitingEnabled(boolean);
     method public void updateNotificationChannel(@NonNull String, int, @NonNull android.app.NotificationChannel);
   }
 
@@ -447,6 +449,11 @@
 
 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);
   }
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 55df824..55b858e 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -5151,12 +5151,6 @@
      * #checkSelfPermission(String)}.
      * </p>
      * <p>
-     * Calling this API for permissions already granted to your app would show UI
-     * to the user to decide whether the app can still hold these permissions. This
-     * can be useful if the way your app uses data guarded by the permissions
-     * changes significantly.
-     * </p>
-     * <p>
      * You cannot request a permission if your activity sets {@link
      * android.R.styleable#AndroidManifestActivity_noHistory noHistory} to
      * <code>true</code> because in this case the activity would not receive
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 697a377..bda2fa9 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -228,4 +228,6 @@
 
     NotificationListenerFilter getListenerFilter(in ComponentName cn, int userId);
     void setListenerFilter(in ComponentName cn, int userId, in NotificationListenerFilter nlf);
+
+    void setToastRateLimitingEnabled(boolean enable);
 }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index e56274a..5fbc948 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -102,6 +102,7 @@
 import java.lang.reflect.Array;
 import java.lang.reflect.Constructor;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
@@ -645,6 +646,11 @@
      */
     public static final int FLAG_IMMEDIATE_FGS_DISPLAY = 0x00002000;
 
+    private static final List<Class<? extends Style>> PLATFORM_STYLE_CLASSES = Arrays.asList(
+            BigTextStyle.class, BigPictureStyle.class, InboxStyle.class, MediaStyle.class,
+            DecoratedCustomViewStyle.class, DecoratedMediaCustomViewStyle.class,
+            MessagingStyle.class);
+
     /** @hide */
     @IntDef(flag = true, prefix = { "FLAG_" }, value = {FLAG_SHOW_LIGHTS, FLAG_ONGOING_EVENT,
             FLAG_INSISTENT, FLAG_ONLY_ALERT_ONCE,
@@ -5099,7 +5105,7 @@
             final int max = ex.getInt(EXTRA_PROGRESS_MAX, 0);
             final int progress = ex.getInt(EXTRA_PROGRESS, 0);
             final boolean ind = ex.getBoolean(EXTRA_PROGRESS_INDETERMINATE);
-            if (p.hasProgress && (max != 0 || ind)) {
+            if (!p.mHideProgress && (max != 0 || ind)) {
                 contentView.setViewVisibility(com.android.internal.R.id.progress, View.VISIBLE);
                 contentView.setProgressBar(
                         R.id.progress, max, progress, ind);
@@ -5427,7 +5433,7 @@
             int N = nonContextualActions.size();
             boolean emphazisedMode = mN.fullScreenIntent != null;
             big.setBoolean(R.id.actions, "setEmphasizedMode", emphazisedMode);
-            if (N > 0) {
+            if (N > 0 && !p.mHideActions) {
                 big.setViewVisibility(R.id.actions_container, View.VISIBLE);
                 big.setViewVisibility(R.id.actions, View.VISIBLE);
                 big.setViewLayoutMarginDimen(R.id.notification_action_list_margin_target,
@@ -5520,6 +5526,71 @@
             return createContentView(false /* increasedheight */ );
         }
 
+        // This code is executed on behalf of other apps' notifications, sometimes even by 3p apps,
+        // a use case that is not supported by the Compat Framework library.  Workarounds to resolve
+        // the change's state in NotificationManagerService were very complex. While it's possible
+        // apps can detect the change, it's most likely that the changes will simply result in
+        // visual regressions.
+        @SuppressWarnings("AndroidFrameworkCompatChange")
+        private boolean fullyCustomViewRequiresDecoration(boolean fromStyle) {
+            // Custom views which come from a platform style class are safe, and thus do not need to
+            // be wrapped.  Any subclass of those styles has the opportunity to make arbitrary
+            // changes to the RemoteViews, and thus can't be trusted as a fully vetted view.
+            if (fromStyle && PLATFORM_STYLE_CLASSES.contains(mStyle.getClass())) {
+                return false;
+            }
+            final ContentResolver contentResolver = mContext.getContentResolver();
+            final int decorationType = DevFlags.getFullyCustomViewNotifDecoration(contentResolver);
+            return decorationType != DevFlags.DECORATION_NONE
+                    && (DevFlags.shouldBackportSNotifRules(contentResolver)
+                    || mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.S);
+        }
+
+        private RemoteViews minimallyDecoratedContentView(@NonNull RemoteViews customContent) {
+            int decorationType =
+                    DevFlags.getFullyCustomViewNotifDecoration(mContext.getContentResolver());
+            StandardTemplateParams p = mParams.reset()
+                    .viewType(StandardTemplateParams.VIEW_TYPE_NORMAL)
+                    .decorationType(decorationType)
+                    .fillTextsFrom(this);
+            TemplateBindResult result = new TemplateBindResult();
+            RemoteViews standard = applyStandardTemplate(getBaseLayoutResource(), p, result);
+            buildCustomContentIntoTemplate(mContext, standard, customContent,
+                    p, result, decorationType);
+            return standard;
+        }
+
+        private RemoteViews minimallyDecoratedBigContentView(@NonNull RemoteViews customContent) {
+            int decorationType =
+                    DevFlags.getFullyCustomViewNotifDecoration(mContext.getContentResolver());
+            StandardTemplateParams p = mParams.reset()
+                    .viewType(StandardTemplateParams.VIEW_TYPE_BIG)
+                    .decorationType(decorationType)
+                    .fillTextsFrom(this);
+            TemplateBindResult result = new TemplateBindResult();
+            RemoteViews standard = applyStandardTemplateWithActions(getBigBaseLayoutResource(),
+                    p, result);
+            buildCustomContentIntoTemplate(mContext, standard, customContent,
+                    p, result, decorationType);
+            return standard;
+        }
+
+        private RemoteViews minimallyDecoratedHeadsUpContentView(
+                @NonNull RemoteViews customContent) {
+            int decorationType =
+                    DevFlags.getFullyCustomViewNotifDecoration(mContext.getContentResolver());
+            StandardTemplateParams p = mParams.reset()
+                    .viewType(StandardTemplateParams.VIEW_TYPE_HEADS_UP)
+                    .decorationType(decorationType)
+                    .fillTextsFrom(this);
+            TemplateBindResult result = new TemplateBindResult();
+            RemoteViews standard = applyStandardTemplateWithActions(getHeadsUpBaseLayoutResource(),
+                    p, result);
+            buildCustomContentIntoTemplate(mContext, standard, customContent,
+                    p, result, decorationType);
+            return standard;
+        }
+
         /**
          * Construct a RemoteViews for the smaller content view.
          *
@@ -5532,11 +5603,13 @@
          */
         public RemoteViews createContentView(boolean increasedHeight) {
             if (mN.contentView != null && useExistingRemoteView()) {
-                return mN.contentView;
+                return fullyCustomViewRequiresDecoration(false /* fromStyle */)
+                        ? minimallyDecoratedContentView(mN.contentView) : mN.contentView;
             } else if (mStyle != null) {
                 final RemoteViews styleView = mStyle.makeContentView(increasedHeight);
                 if (styleView != null) {
-                    return styleView;
+                    return fullyCustomViewRequiresDecoration(true /* fromStyle */)
+                            ? minimallyDecoratedContentView(styleView) : styleView;
                 }
             }
             StandardTemplateParams p = mParams.reset()
@@ -5556,18 +5629,30 @@
         public RemoteViews createBigContentView() {
             RemoteViews result = null;
             if (mN.bigContentView != null && useExistingRemoteView()) {
-                return mN.bigContentView;
+                return fullyCustomViewRequiresDecoration(false /* fromStyle */)
+                        ? minimallyDecoratedBigContentView(mN.bigContentView) : mN.bigContentView;
             }
             if (mStyle != null) {
                 result = mStyle.makeBigContentView();
                 hideLine1Text(result);
+                if (fullyCustomViewRequiresDecoration(true /* fromStyle */)) {
+                    result = minimallyDecoratedBigContentView(result);
+                }
             }
-            if (result == null && bigContentViewRequired()) {
-                StandardTemplateParams p = mParams.reset()
-                        .viewType(StandardTemplateParams.VIEW_TYPE_BIG)
-                        .fillTextsFrom(this);
-                result = applyStandardTemplateWithActions(getBigBaseLayoutResource(), p,
-                        null /* result */);
+            if (result == null) {
+                if (bigContentViewRequired()) {
+                    StandardTemplateParams p = mParams.reset()
+                            .viewType(StandardTemplateParams.VIEW_TYPE_BIG)
+                            .fillTextsFrom(this);
+                    result = applyStandardTemplateWithActions(getBigBaseLayoutResource(), p,
+                            null /* result */);
+                } else if (DevFlags.shouldBackportSNotifRules(mContext.getContentResolver())
+                        && useExistingRemoteView()
+                        && fullyCustomViewRequiresDecoration(false /* fromStyle */)) {
+                    // This "backport" logic is a special case to handle the UNDO style of notif
+                    // so that we can see what that will look like when the app targets S.
+                    result = minimallyDecoratedBigContentView(mN.contentView);
+                }
             }
             makeHeaderExpanded(result);
             return result;
@@ -5661,11 +5746,14 @@
          */
         public RemoteViews createHeadsUpContentView(boolean increasedHeight) {
             if (mN.headsUpContentView != null && useExistingRemoteView()) {
-                return mN.headsUpContentView;
+                return fullyCustomViewRequiresDecoration(false /* fromStyle */)
+                        ? minimallyDecoratedHeadsUpContentView(mN.headsUpContentView)
+                        : mN.headsUpContentView;
             } else if (mStyle != null) {
                 final RemoteViews styleView = mStyle.makeHeadsUpContentView(increasedHeight);
                 if (styleView != null) {
-                    return styleView;
+                    return fullyCustomViewRequiresDecoration(true /* fromStyle */)
+                            ? minimallyDecoratedHeadsUpContentView(styleView) : styleView;
                 }
             } else if (mActions.size() == 0) {
                 return null;
@@ -5677,8 +5765,7 @@
                     .viewType(StandardTemplateParams.VIEW_TYPE_HEADS_UP)
                     .fillTextsFrom(this)
                     .setMaxRemoteInputHistory(1);
-            return applyStandardTemplateWithActions(getHeadsUpBaseLayoutResource(),
-                    p,
+            return applyStandardTemplateWithActions(getHeadsUpBaseLayoutResource(), p,
                     null /* result */);
         }
 
@@ -6596,11 +6683,7 @@
      */
     @SystemApi
     public static Class<? extends Style> getNotificationStyleClass(String templateClass) {
-        Class<? extends Style>[] classes = new Class[] {
-                BigTextStyle.class, BigPictureStyle.class, InboxStyle.class, MediaStyle.class,
-                DecoratedCustomViewStyle.class, DecoratedMediaCustomViewStyle.class,
-                MessagingStyle.class };
-        for (Class<? extends Style> innerClass : classes) {
+        for (Class<? extends Style> innerClass : PLATFORM_STYLE_CLASSES) {
             if (templateClass.equals(innerClass.getName())) {
                 return innerClass;
             }
@@ -6608,6 +6691,56 @@
         return null;
     }
 
+    private static void buildCustomContentIntoTemplate(@NonNull Context context,
+            @NonNull RemoteViews template, @Nullable RemoteViews customContent,
+            @NonNull StandardTemplateParams p, @NonNull TemplateBindResult result,
+            int decorationType) {
+        int childIndex = -1;
+        if (customContent != null) {
+            // Need to clone customContent before adding, because otherwise it can no longer be
+            // parceled independently of remoteViews.
+            customContent = customContent.clone();
+            if (p.mHeaderless) {
+                if (decorationType <= DevFlags.DECORATION_PARTIAL) {
+                    template.removeFromParent(R.id.notification_top_line);
+                }
+                if (decorationType != DevFlags.DECORATION_FULL_COMPATIBLE) {
+                    // Change the max content size from 60dp (the compatible size) to 48dp
+                    // (the constrained size).  This is done by increasing the minimum margin
+                    // (implemented as top/bottom margins) and decreasing the extra margin
+                    // (implemented as the height of shrinkable top/bottom views in the column).
+                    template.setViewLayoutMarginDimen(
+                            R.id.notification_headerless_view_column,
+                            RemoteViews.MARGIN_TOP,
+                            R.dimen.notification_headerless_margin_constrained_minimum);
+                    template.setViewLayoutMarginDimen(
+                            R.id.notification_headerless_view_column,
+                            RemoteViews.MARGIN_BOTTOM,
+                            R.dimen.notification_headerless_margin_constrained_minimum);
+                    template.setViewLayoutHeightDimen(
+                            R.id.notification_headerless_margin_extra_top,
+                            R.dimen.notification_headerless_margin_constrained_extra);
+                    template.setViewLayoutHeightDimen(
+                            R.id.notification_headerless_margin_extra_bottom,
+                            R.dimen.notification_headerless_margin_constrained_extra);
+                }
+            } else {
+                // also update the end margin to account for the large icon or expander
+                Resources resources = context.getResources();
+                result.mTitleMarginSet.applyToView(template, R.id.notification_main_column,
+                        resources.getDimension(R.dimen.notification_content_margin_end)
+                                / resources.getDisplayMetrics().density);
+            }
+            template.removeAllViewsExceptId(R.id.notification_main_column, R.id.progress);
+            template.addView(R.id.notification_main_column, customContent, 0 /* index */);
+            template.addFlags(RemoteViews.FLAG_REAPPLY_DISALLOWED);
+            childIndex = 0;
+        }
+        template.setIntTag(R.id.notification_main_column,
+                com.android.internal.R.id.notification_custom_view_index_tag,
+                childIndex);
+    }
+
     /**
      * An object that can apply a rich notification style to a {@link Notification.Builder}
      * object.
@@ -7813,7 +7946,7 @@
             StandardTemplateParams p = mBuilder.mParams.reset()
                     .viewType(isCollapsed ? StandardTemplateParams.VIEW_TYPE_NORMAL
                             : StandardTemplateParams.VIEW_TYPE_BIG)
-                    .hasProgress(false)
+                    .hideProgress(true)
                     .title(conversationTitle)
                     .text(null)
                     .hideLargeIcon(hideRightIcons || isOneToOne)
@@ -8628,7 +8761,8 @@
         private RemoteViews makeMediaContentView() {
             StandardTemplateParams p = mBuilder.mParams.reset()
                     .viewType(StandardTemplateParams.VIEW_TYPE_NORMAL)
-                    .hasProgress(false).fillTextsFrom(mBuilder);
+                    .hideProgress(true)
+                    .fillTextsFrom(mBuilder);
             RemoteViews view = mBuilder.applyStandardTemplate(
                     R.layout.notification_template_material_media, p,
                     null /* result */);
@@ -8677,7 +8811,8 @@
             }
             StandardTemplateParams p = mBuilder.mParams.reset()
                     .viewType(StandardTemplateParams.VIEW_TYPE_BIG)
-                    .hasProgress(false).fillTextsFrom(mBuilder);
+                    .hideProgress(true)
+                    .fillTextsFrom(mBuilder);
             RemoteViews big = mBuilder.applyStandardTemplate(
                     R.layout.notification_template_material_big_media, p , null /* result */);
 
@@ -8771,29 +8906,39 @@
             RemoteViews headsUpContentView = mBuilder.mN.headsUpContentView == null
                     ? mBuilder.mN.contentView
                     : mBuilder.mN.headsUpContentView;
+            if (headsUpContentView == null) {
+                return null;  // no custom view; use the default behavior
+            }
             if (mBuilder.mActions.size() == 0) {
                return makeStandardTemplateWithCustomContent(headsUpContentView);
             }
+            int decorationType = getDecorationType();
             TemplateBindResult result = new TemplateBindResult();
             StandardTemplateParams p = mBuilder.mParams.reset()
                     .viewType(StandardTemplateParams.VIEW_TYPE_HEADS_UP)
-                    .hasCustomContent(headsUpContentView != null)
+                    .decorationType(decorationType)
                     .fillTextsFrom(mBuilder);
             RemoteViews remoteViews = mBuilder.applyStandardTemplateWithActions(
                     mBuilder.getHeadsUpBaseLayoutResource(), p, result);
-            buildIntoRemoteViewContent(remoteViews, headsUpContentView, result, true);
+            buildCustomContentIntoTemplate(mBuilder.mContext, remoteViews, headsUpContentView,
+                    p, result, decorationType);
             return remoteViews;
         }
 
         private RemoteViews makeStandardTemplateWithCustomContent(RemoteViews customContent) {
+            if (customContent == null) {
+                return null;  // no custom view; use the default behavior
+            }
+            int decorationType = getDecorationType();
             TemplateBindResult result = new TemplateBindResult();
             StandardTemplateParams p = mBuilder.mParams.reset()
                     .viewType(StandardTemplateParams.VIEW_TYPE_NORMAL)
-                    .hasCustomContent(customContent != null)
+                    .decorationType(decorationType)
                     .fillTextsFrom(mBuilder);
             RemoteViews remoteViews = mBuilder.applyStandardTemplate(
                     mBuilder.getBaseLayoutResource(), p, result);
-            buildIntoRemoteViewContent(remoteViews, customContent, result, true);
+            buildCustomContentIntoTemplate(mBuilder.mContext, remoteViews, customContent,
+                    p, result, decorationType);
             return remoteViews;
         }
 
@@ -8801,38 +8946,37 @@
             RemoteViews bigContentView = mBuilder.mN.bigContentView == null
                     ? mBuilder.mN.contentView
                     : mBuilder.mN.bigContentView;
+            if (bigContentView == null) {
+                return null;  // no custom view; use the default behavior
+            }
+            int decorationType = getDecorationType();
             TemplateBindResult result = new TemplateBindResult();
             StandardTemplateParams p = mBuilder.mParams.reset()
                     .viewType(StandardTemplateParams.VIEW_TYPE_BIG)
-                    .hasCustomContent(bigContentView != null)
+                    .decorationType(decorationType)
                     .fillTextsFrom(mBuilder);
             RemoteViews remoteViews = mBuilder.applyStandardTemplateWithActions(
                     mBuilder.getBigBaseLayoutResource(), p, result);
-            buildIntoRemoteViewContent(remoteViews, bigContentView, result, false);
+            buildCustomContentIntoTemplate(mBuilder.mContext, remoteViews, bigContentView,
+                    p, result, decorationType);
             return remoteViews;
         }
 
-        private void buildIntoRemoteViewContent(RemoteViews remoteViews,
-                RemoteViews customContent, TemplateBindResult result, boolean headerless) {
-            int childIndex = -1;
-            if (customContent != null) {
-                // Need to clone customContent before adding, because otherwise it can no longer be
-                // parceled independently of remoteViews.
-                customContent = customContent.clone();
-                remoteViews.removeAllViewsExceptId(R.id.notification_main_column, R.id.progress);
-                remoteViews.addView(R.id.notification_main_column, customContent, 0 /* index */);
-                remoteViews.addFlags(RemoteViews.FLAG_REAPPLY_DISALLOWED);
-                childIndex = 0;
-            }
-            remoteViews.setIntTag(R.id.notification_main_column,
-                    com.android.internal.R.id.notification_custom_view_index_tag,
-                    childIndex);
-            if (!headerless) {
-                // also update the end margin to account for the large icon or expander
-                Resources resources = mBuilder.mContext.getResources();
-                result.mTitleMarginSet.applyToView(remoteViews, R.id.notification_main_column,
-                        resources.getDimension(R.dimen.notification_content_margin_end)
-                                / resources.getDisplayMetrics().density);
+        // This code is executed on behalf of other apps' notifications, sometimes even by 3p apps,
+        // a use case that is not supported by the Compat Framework library.  Workarounds to resolve
+        // the change's state in NotificationManagerService were very complex. While it's possible
+        // apps can detect the change, it's most likely that the changes will simply result in
+        // visual regressions.
+        @SuppressWarnings("AndroidFrameworkCompatChange")
+        private int getDecorationType() {
+            ContentResolver contentResolver = mBuilder.mContext.getContentResolver();
+            if (mBuilder.mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.S
+                    || DevFlags.shouldBackportSNotifRules(contentResolver)) {
+                return DevFlags.getDecoratedCustomViewNotifDecoration(contentResolver);
+            } else {
+                // For apps that don't target S, this decoration provides the closest behavior to R,
+                // but doesn't fit with the design guidelines for S.
+                return DevFlags.DECORATION_FULL_COMPATIBLE;
             }
         }
 
@@ -11159,8 +11303,9 @@
 
         int mViewType = VIEW_TYPE_UNSPECIFIED;
         boolean mHeaderless;
-        boolean mHasCustomContent;
-        boolean hasProgress = true;
+        boolean mHideTitle;
+        boolean mHideActions;
+        boolean mHideProgress;
         CharSequence title;
         CharSequence text;
         CharSequence headerTextSecondary;
@@ -11173,8 +11318,9 @@
         final StandardTemplateParams reset() {
             mViewType = VIEW_TYPE_UNSPECIFIED;
             mHeaderless = false;
-            mHasCustomContent = false;
-            hasProgress = true;
+            mHideTitle = false;
+            mHideActions = false;
+            mHideProgress = false;
             title = null;
             text = null;
             summaryText = null;
@@ -11186,9 +11332,7 @@
         }
 
         final boolean hasTitle() {
-            // We hide the title when the notification is a decorated custom view so that decorated
-            // custom views always have to include their own title.
-            return !TextUtils.isEmpty(title) && !mHasCustomContent;
+            return !TextUtils.isEmpty(title) && !mHideTitle;
         }
 
         final StandardTemplateParams viewType(int viewType) {
@@ -11201,13 +11345,18 @@
             return this;
         }
 
-        final StandardTemplateParams hasProgress(boolean hasProgress) {
-            this.hasProgress = hasProgress;
+        final StandardTemplateParams hideActions(boolean hideActions) {
+            this.mHideActions = hideActions;
             return this;
         }
 
-        final StandardTemplateParams hasCustomContent(boolean hasCustomContent) {
-            this.mHasCustomContent = hasCustomContent;
+        final StandardTemplateParams hideProgress(boolean hideProgress) {
+            this.mHideProgress = hideProgress;
+            return this;
+        }
+
+        final StandardTemplateParams hideTitle(boolean hideTitle) {
+            this.mHideTitle = hideTitle;
             return this;
         }
 
@@ -11263,6 +11412,16 @@
             this.maxRemoteInputHistory = maxRemoteInputHistory;
             return this;
         }
+
+        public StandardTemplateParams decorationType(int decorationType) {
+            boolean hideTitle = decorationType <= DevFlags.DECORATION_FULL_COMPATIBLE;
+            boolean hideOtherFields = decorationType <= DevFlags.DECORATION_MINIMAL;
+            hideTitle(hideTitle);
+            hideLargeIcon(hideOtherFields);
+            hideProgress(hideOtherFields);
+            hideActions(hideOtherFields);
+            return this;
+        }
     }
 
     /**
@@ -11272,7 +11431,67 @@
      * @hide
      */
     public static class DevFlags {
+
+        /**
+         * Notifications will not be decorated.  The custom content will be shown as-is.
+         *
+         * <p>NOTE: This option is not available for notifications with DecoratedCustomViewStyle,
+         * as that API contract includes decorations that this does not provide.
+         */
+        public static final int DECORATION_NONE = 0;
+
+        /**
+         * Notifications will be minimally decorated with ONLY an icon and expander as follows:
+         * <li>A large icon is never shown.
+         * <li>A progress bar is never shown.
+         * <li>The expanded and heads up states do not show actions, even if provided.
+         * <li>The collapsed state gives the app's custom content 48dp of vertical space.
+         * <li>The collapsed state does NOT include the top line of views,
+         * like the alerted icon or work profile badge.
+         *
+         * <p>NOTE: This option is not available for notifications with DecoratedCustomViewStyle,
+         * as that API contract includes decorations that this does not provide.
+         */
+        public static final int DECORATION_MINIMAL = 1;
+
+        /**
+         * Notifications will be partially decorated with AT LEAST an icon and expander as follows:
+         * <li>A large icon is shown if provided.
+         * <li>A progress bar is shown if provided and enough space remains below the content.
+         * <li>Actions are shown in the expanded and heads up states.
+         * <li>The collapsed state gives the app's custom content 48dp of vertical space.
+         * <li>The collapsed state does NOT include the top line of views,
+         * like the alerted icon or work profile badge.
+         */
+        public static final int DECORATION_PARTIAL = 2;
+
+        /**
+         * Notifications will be fully decorated as follows:
+         * <li>A large icon is shown if provided.
+         * <li>A progress bar is shown if provided and enough space remains below the content.
+         * <li>Actions are shown in the expanded and heads up states.
+         * <li>The collapsed state gives the app's custom content 40dp of vertical space.
+         * <li>The collapsed state DOES include the top line of views,
+         * like the alerted icon or work profile badge.
+         * <li>The collapsed state's top line views will never show the title text.
+         */
+        public static final int DECORATION_FULL_COMPATIBLE = 3;
+
+        /**
+         * Notifications will be fully decorated as follows:
+         * <li>A large icon is shown if provided.
+         * <li>A progress bar is shown if provided and enough space remains below the content.
+         * <li>Actions are shown in the expanded and heads up states.
+         * <li>The collapsed state gives the app's custom content 20dp of vertical space.
+         * <li>The collapsed state DOES include the top line of views
+         * like the alerted icon or work profile badge.
+         * <li>The collapsed state's top line views will contain the title text if provided.
+         */
+        public static final int DECORATION_FULL_CONSTRAINED = 4;
+
         private static final boolean DEFAULT_BACKPORT_S_NOTIF_RULES = false;
+        private static final int DEFAULT_FULLY_CUSTOM_DECORATION = DECORATION_MINIMAL;
+        private static final int DEFAULT_DECORATED_DECORATION = DECORATION_PARTIAL;
 
         /**
          * Used by unit tests to force that this class returns its default values, which is required
@@ -11292,5 +11511,37 @@
             return Settings.Global.getInt(contentResolver, Settings.Global.BACKPORT_S_NOTIF_RULES,
                         DEFAULT_BACKPORT_S_NOTIF_RULES ? 1 : 0) == 1;
         }
+
+        /**
+         * @return the decoration type to be applied to notifications with fully custom view.
+         * @hide
+         */
+        public static int getFullyCustomViewNotifDecoration(
+                @NonNull ContentResolver contentResolver) {
+            if (sForceDefaults) {
+                return DEFAULT_FULLY_CUSTOM_DECORATION;
+            }
+            final int decoration = Settings.Global.getInt(contentResolver,
+                    Settings.Global.FULLY_CUSTOM_VIEW_NOTIF_DECORATION,
+                    DEFAULT_FULLY_CUSTOM_DECORATION);
+            // clamp to a valid decoration value
+            return Math.max(DECORATION_NONE, Math.min(decoration, DECORATION_FULL_CONSTRAINED));
+        }
+
+        /**
+         * @return the decoration type to be applied to notifications with DecoratedCustomViewStyle.
+         * @hide
+         */
+        public static int getDecoratedCustomViewNotifDecoration(
+                @NonNull ContentResolver contentResolver) {
+            if (sForceDefaults) {
+                return DEFAULT_DECORATED_DECORATION;
+            }
+            final int decoration = Settings.Global.getInt(contentResolver,
+                    Settings.Global.DECORATED_CUSTOM_VIEW_NOTIF_DECORATION,
+                    DEFAULT_DECORATED_DECORATION);
+            // clamp to a valid decoration value (and don't allow decoration to be NONE or MINIMAL)
+            return Math.max(DECORATION_PARTIAL, Math.min(decoration, DECORATION_FULL_CONSTRAINED));
+        }
     }
 }
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 58f382d..6cce270 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1730,6 +1730,23 @@
     }
 
     /**
+     * Controls whether toast rate limiting is enabled for the calling uid.
+     *
+     * @param enable true to enable toast rate limiting, false to disable it
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_TOAST_RATE_LIMITING)
+    public void setToastRateLimitingEnabled(boolean enable) {
+        INotificationManager service = getService();
+        try {
+            service.setToastRateLimitingEnabled(enable);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Notification policy configuration.  Represents user-preferences for notification
      * filtering.
      */
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index 06ad9c9..c804e642 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -2,6 +2,33 @@
 # Remain no owner because multiple modules may touch this file.
 per-file ContextImpl.java = *
 
+# ActivityManager
+per-file ActivityManager* = file:/services/core/java/com/android/server/am/OWNERS
+per-file ApplicationErrorReport* = file:/services/core/java/com/android/server/am/OWNERS
+per-file ApplicationExitInfo* = file:/services/core/java/com/android/server/am/OWNERS
+per-file Application.java = file:/services/core/java/com/android/server/am/OWNERS
+per-file ApplicationLoaders.java = file:/services/core/java/com/android/server/am/OWNERS
+per-file ApplicationThreadConstants.java = file:/services/core/java/com/android/server/am/OWNERS
+per-file BroadcastOptions.java = file:/services/core/java/com/android/server/am/OWNERS
+per-file ContentProviderHolder* = file:/services/core/java/com/android/server/am/OWNERS
+per-file IActivityController.aidl = file:/services/core/java/com/android/server/am/OWNERS
+per-file IActivityManager.aidl = file:/services/core/java/com/android/server/am/OWNERS
+per-file IApplicationThread.aidl = file:/services/core/java/com/android/server/am/OWNERS
+per-file IAppTraceRetriever.aidl = file:/services/core/java/com/android/server/am/OWNERS
+per-file IInstrumentationWatcher.aidl = file:/services/core/java/com/android/server/am/OWNERS
+per-file IntentService.aidl = file:/services/core/java/com/android/server/am/OWNERS
+per-file IServiceConnection.aidl = file:/services/core/java/com/android/server/am/OWNERS
+per-file IStopUserCallback.aidl = file:/services/core/java/com/android/server/am/OWNERS
+per-file IUidObserver.aidl = file:/services/core/java/com/android/server/am/OWNERS
+per-file LoadedApk.java = file:/services/core/java/com/android/server/am/OWNERS
+per-file LocalActivityManager.java = file:/services/core/java/com/android/server/am/OWNERS
+per-file PendingIntent* = file:/services/core/java/com/android/server/am/OWNERS
+per-file *Process* = file:/services/core/java/com/android/server/am/OWNERS
+per-file ProfilerInfo* = file:/services/core/java/com/android/server/am/OWNERS
+per-file Service* = file:/services/core/java/com/android/server/am/OWNERS
+per-file SystemServiceRegistry.java = file:/services/core/java/com/android/server/am/OWNERS
+per-file *UserSwitchObserver* = file:/services/core/java/com/android/server/am/OWNERS
+
 # ActivityThread
 per-file ActivityThread.java = file:/services/core/java/com/android/server/am/OWNERS
 per-file ActivityThread.java = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 2ce0e87..050d194 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -29,7 +29,9 @@
 import android.app.contentsuggestions.ContentSuggestionsManager;
 import android.app.contentsuggestions.IContentSuggestionsManager;
 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;
@@ -585,6 +587,13 @@
                 return new NsdManager(ctx.getOuterContext(), service);
             }});
 
+        registerService(Context.PEOPLE_SERVICE, PeopleManager.class,
+                new CachedServiceFetcher<PeopleManager>() {
+            @Override
+            public PeopleManager createService(ContextImpl ctx) throws ServiceNotFoundException {
+                return new PeopleManager(ctx);
+            }});
+
         registerService(Context.POWER_SERVICE, PowerManager.class,
                 new CachedServiceFetcher<PowerManager>() {
             @Override
@@ -1290,6 +1299,14 @@
                         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/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 806cb49..97879b8 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -39,7 +39,6 @@
 import android.app.Activity;
 import android.app.IServiceConnection;
 import android.app.KeyguardManager;
-import android.app.admin.DevicePolicyManager.DevicePolicyOperation;
 import android.app.admin.SecurityLog.SecurityEvent;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
@@ -306,7 +305,13 @@
      * of the provisioning flow was successful, although this doesn't guarantee the full flow will
      * succeed. Conversely a result code of {@link android.app.Activity#RESULT_CANCELED} implies
      * that the user backed-out of provisioning, or some precondition for provisioning wasn't met.
+     *
+     * @deprecated admin apps must now implement activities with intent filters for the {@link
+     * #ACTION_GET_PROVISIONING_MODE} and {@link #ACTION_ADMIN_POLICY_COMPLIANCE} intent actions;
+     * using {@link #ACTION_PROVISION_MANAGED_DEVICE} to start provisioning will cause the
+     * provisioning to fail.
      */
+    @Deprecated
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_PROVISION_MANAGED_DEVICE
         = "android.app.action.PROVISION_MANAGED_DEVICE";
@@ -598,6 +603,12 @@
      * properties will be converted into a {@link android.os.PersistableBundle} and passed to the
      * management application after provisioning.
      *
+     * <p>Admin apps will receive this extra in their {@link #ACTION_GET_PROVISIONING_MODE} and
+     * {@link #ACTION_ADMIN_POLICY_COMPLIANCE} intent handlers. Additionally, {@link
+     * #ACTION_GET_PROVISIONING_MODE} may also return this extra which will then be sent over to
+     * {@link #ACTION_ADMIN_POLICY_COMPLIANCE}, alongside the original values that were passed to
+     * {@link #ACTION_GET_PROVISIONING_MODE}.
+     *
      * <p>
      * In both cases the application receives the data in
      * {@link DeviceAdminReceiver#onProfileProvisioningComplete} via an intent with the action
@@ -655,7 +666,9 @@
      * profile provisioning. If the account supplied is present in the primary user, it will be
      * copied, along with its credentials to the managed profile and removed from the primary user.
      *
-     * Use with {@link #ACTION_PROVISION_MANAGED_PROFILE}.
+     * Use with {@link #ACTION_PROVISION_MANAGED_PROFILE}, with managed account provisioning, or
+     * return as an extra to the intent result from the {@link #ACTION_GET_PROVISIONING_MODE}
+     * activity.
      */
 
     public static final String EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE
@@ -669,8 +682,10 @@
      *
      * <p> Defaults to {@code false}
      *
-     * <p> Use with {@link #ACTION_PROVISION_MANAGED_PROFILE} and
-     * {@link #EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE}
+     * <p> Use with {@link #ACTION_PROVISION_MANAGED_PROFILE} or set as an extra to the
+     * intent result of the {@link #ACTION_GET_PROVISIONING_MODE} activity.
+     *
+     * @see #EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE
      */
     public static final String EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION
             = "android.app.extra.PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION";
@@ -697,8 +712,9 @@
      * A Boolean extra that can be used by the mobile device management application to skip the
      * disabling of system apps during provisioning when set to {@code true}.
      *
-     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} or an intent with action
-     * {@link #ACTION_PROVISION_MANAGED_DEVICE} that starts device owner provisioning.
+     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC}, an intent with action
+     * {@link #ACTION_PROVISION_MANAGED_PROFILE} that starts profile owner provisioning or
+     * set as an extra to the intent result of the {@link #ACTION_GET_PROVISIONING_MODE} activity.
      */
     public static final String EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED =
             "android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED";
@@ -1175,27 +1191,15 @@
             "android.app.extra.PROVISIONING_DISCLAIMER_CONTENT";
 
     /**
-     * A boolean extra indicating if user setup should be skipped, for when provisioning is started
-     * during setup-wizard.
-     *
-     * <p>If unspecified, defaults to {@code true} to match the behavior in
-     * {@link android.os.Build.VERSION_CODES#M} and earlier.
-     *
-     * <p>Use in an intent with action {@link #ACTION_PROVISION_MANAGED_DEVICE} or
-     * {@link #ACTION_PROVISION_MANAGED_USER}.
-     *
-     * @hide
-     */
-    public static final String EXTRA_PROVISIONING_SKIP_USER_SETUP =
-            "android.app.extra.PROVISIONING_SKIP_USER_SETUP";
-
-    /**
      * A boolean extra indicating if the user consent steps from the provisioning flow should be
      * skipped. If unspecified, defaults to {@code false}.
      *
      * It can only be used by an existing device owner trying to create a managed profile via
      * {@link #ACTION_PROVISION_MANAGED_PROFILE}. Otherwise it is ignored.
+     *
+     * @deprecated this extra is no longer relevant as device owners cannot create managed profiles
      */
+    @Deprecated
     public static final String EXTRA_PROVISIONING_SKIP_USER_CONSENT =
             "android.app.extra.PROVISIONING_SKIP_USER_CONSENT";
 
@@ -1252,7 +1256,8 @@
     @IntDef(prefix = { "SUPPORTED_MODES_" }, value = {
             SUPPORTED_MODES_ORGANIZATION_OWNED,
             SUPPORTED_MODES_PERSONALLY_OWNED,
-            SUPPORTED_MODES_ORGANIZATION_AND_PERSONALLY_OWNED
+            SUPPORTED_MODES_ORGANIZATION_AND_PERSONALLY_OWNED,
+            SUPPORTED_MODES_DEVICE_OWNER
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ProvisioningConfiguration {}
@@ -1379,6 +1384,15 @@
     public static final int SUPPORTED_MODES_ORGANIZATION_AND_PERSONALLY_OWNED = 3;
 
     /**
+     * A value for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES} indicating that the only supported
+     * provisioning mode is device owner.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int SUPPORTED_MODES_DEVICE_OWNER = 4;
+
+    /**
      * This MIME type is used for starting the device owner provisioning.
      *
      * <p>During device owner provisioning a device admin app is set as the owner of the device.
@@ -2456,6 +2470,16 @@
      * <p>The target activity may also return the account that needs to be migrated from primary
      * user to managed profile in case of a profile owner provisioning in
      * {@link #EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE} as result.
+     *
+     * <p>The target activity may also include the {@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}
+     * extra in the intent result. The values of this {@link android.os.PersistableBundle} will be
+     * sent as an intent extra of the same name to the {@link #ACTION_ADMIN_POLICY_COMPLIANCE}
+     * activity, along with the values of the {@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE} extra
+     * that are already supplied to this activity.
+     *
+     * @see #EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION
+     * @see #EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED
+     * @see #ACTION_ADMIN_POLICY_COMPLIANCE
      */
     public static final String ACTION_GET_PROVISIONING_MODE =
             "android.app.action.GET_PROVISIONING_MODE";
@@ -2504,6 +2528,7 @@
      * @see #SUPPORTED_MODES_ORGANIZATION_OWNED
      * @see #SUPPORTED_MODES_PERSONALLY_OWNED
      * @see #SUPPORTED_MODES_ORGANIZATION_AND_PERSONALLY_OWNED
+     * @see #SUPPORTED_MODES_DEVICE_OWNER
      * @hide
      */
     @SystemApi
@@ -2545,6 +2570,11 @@
      * provisioning flow (in which case this gets sent after {@link #ACTION_GET_PROVISIONING_MODE}),
      * or it could happen during provisioning finalization if the administrator supports
      * finalization during setup wizard.
+     *
+     * <p>Intents with this action may also be supplied with the {@link
+     * #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE} extra.
+     *
+     * @see #ACTION_GET_PROVISIONING_MODE
      */
     public static final String ACTION_ADMIN_POLICY_COMPLIANCE =
             "android.app.action.ADMIN_POLICY_COMPLIANCE";
@@ -12783,4 +12813,66 @@
             }
         }
     }
+
+    /**
+     * Returns an enrollment-specific identifier of this device, which is guaranteed to be the same
+     * value for the same device, enrolled into the same organization by the same managing app.
+     * This identifier is high-entropy, useful for uniquely identifying individual devices within
+     * the same organisation.
+     * It is available both in a work profile and on a fully-managed device.
+     * The identifier would be consistent even if the work profile is removed and enrolled again
+     * (to the same organization), or the device is factory reset and re-enrolled.
+
+     * Can only be called by the Profile Owner or Device Owner, if the
+     * {@link #setOrganizationId(String)} was previously called.
+     * If {@link #setOrganizationId(String)} was not called, then the returned value will be an
+     * empty string.
+     *
+     * @return A stable, enrollment-specific identifier.
+     * @throws SecurityException if the caller is not a profile owner or device owner.
+     */
+    @NonNull public String getEnrollmentSpecificId() {
+        if (mService == null) {
+            return "";
+        }
+
+        try {
+            return mService.getEnrollmentSpecificId();
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Sets the Enterprise ID for the work profile or managed device. This is a requirement for
+     * generating an enrollment-specific ID for the device, see {@link #getEnrollmentSpecificId()}.
+     *
+     * It is recommended that the Enterprise ID is at least 6 characters long, and no more than
+     * 64 characters.
+     *
+     * @param enterpriseId An identifier of the organization this work profile or device is
+     *                     enrolled into.
+     */
+    public void setOrganizationId(@NonNull String enterpriseId) {
+        setOrganizationIdForUser(mContext.getPackageName(), enterpriseId, myUserId());
+    }
+
+    /**
+     * Sets the Enterprise ID for the work profile or managed device. This is a requirement for
+     * generating an enrollment-specific ID for the device, see
+     * {@link #getEnrollmentSpecificId()}.
+     *
+     * @hide
+     */
+    public void setOrganizationIdForUser(@NonNull String packageName,
+            @NonNull String enterpriseId, @UserIdInt int userId) {
+        if (mService == null) {
+            return;
+        }
+        try {
+            mService.setOrganizationIdForUser(packageName, enterpriseId, userId);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 4b87bb9..e81abfe 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -489,4 +489,7 @@
     boolean canProfileOwnerResetPasswordWhenLocked(int userId);
 
     void setNextOperationSafety(int operation, boolean safe);
+
+    String getEnrollmentSpecificId();
+    void setOrganizationIdForUser(in String callerPackage, in String enterpriseId, int userId);
 }
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 0f7fac4..65a2164 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -672,6 +672,7 @@
         static final int FLAGS_CONTEXT_CLICKABLE = 0x00004000;
         static final int FLAGS_OPAQUE = 0x00008000;
 
+        static final int FLAGS_HAS_MIME_TYPES = 0x80000000;
         static final int FLAGS_HAS_MATRIX = 0x40000000;
         static final int FLAGS_HAS_ALPHA = 0x20000000;
         static final int FLAGS_HAS_ELEVATION = 0x10000000;
@@ -715,6 +716,7 @@
         String mWebDomain;
         Bundle mExtras;
         LocaleList mLocaleList;
+        String[] mOnReceiveContentMimeTypes;
 
         ViewNode[] mChildren;
 
@@ -880,6 +882,9 @@
             if ((flags&FLAGS_HAS_LOCALE_LIST) != 0) {
                 mLocaleList = in.readParcelable(null);
             }
+            if ((flags & FLAGS_HAS_MIME_TYPES) != 0) {
+                mOnReceiveContentMimeTypes = in.readStringArray();
+            }
             if ((flags&FLAGS_HAS_EXTRAS) != 0) {
                 mExtras = in.readBundle();
             }
@@ -939,6 +944,9 @@
             if (mLocaleList != null) {
                 flags |= FLAGS_HAS_LOCALE_LIST;
             }
+            if (mOnReceiveContentMimeTypes != null) {
+                flags |= FLAGS_HAS_MIME_TYPES;
+            }
             if (mExtras != null) {
                 flags |= FLAGS_HAS_EXTRAS;
             }
@@ -1109,6 +1117,9 @@
             if ((flags&FLAGS_HAS_LOCALE_LIST) != 0) {
                 out.writeParcelable(mLocaleList, 0);
             }
+            if ((flags & FLAGS_HAS_MIME_TYPES) != 0) {
+                out.writeStringArray(mOnReceiveContentMimeTypes);
+            }
             if ((flags&FLAGS_HAS_EXTRAS) != 0) {
                 out.writeBundle(mExtras);
             }
@@ -1527,6 +1538,15 @@
         }
 
         /**
+         * Returns the MIME types accepted by {@link View#performReceiveContent} for this view. See
+         * {@link View#getOnReceiveContentMimeTypes()} for details.
+         */
+        @Nullable
+        public String[] getOnReceiveContentMimeTypes() {
+            return mOnReceiveContentMimeTypes;
+        }
+
+        /**
          * Returns any text associated with the node that is displayed to the user, or null
          * if there is none.
          */
@@ -2146,6 +2166,11 @@
         }
 
         @Override
+        public void setOnReceiveContentMimeTypes(@Nullable String[] mimeTypes) {
+            mNode.mOnReceiveContentMimeTypes = mimeTypes;
+        }
+
+        @Override
         public void setInputType(int inputType) {
             mNode.mInputType = inputType;
         }
@@ -2422,6 +2447,10 @@
         if (localeList != null) {
             Log.i(TAG, prefix + "  LocaleList: " + localeList);
         }
+        String[] mimeTypes = node.getOnReceiveContentMimeTypes();
+        if (mimeTypes != null) {
+            Log.i(TAG, prefix + "  MIME types: " + Arrays.toString(mimeTypes));
+        }
         String hint = node.getHint();
         if (hint != null) {
             Log.i(TAG, prefix + "  Hint: " + hint);
diff --git a/core/java/android/app/people/ConversationStatus.aidl b/core/java/android/app/people/ConversationStatus.aidl
new file mode 100644
index 0000000..acfe135
--- /dev/null
+++ b/core/java/android/app/people/ConversationStatus.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.people;
+
+parcelable ConversationStatus;
\ No newline at end of file
diff --git a/core/java/android/app/people/ConversationStatus.java b/core/java/android/app/people/ConversationStatus.java
new file mode 100644
index 0000000..d2a0255
--- /dev/null
+++ b/core/java/android/app/people/ConversationStatus.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.people;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.drawable.Icon;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+public final class ConversationStatus implements Parcelable {
+    private static final String TAG = "ConversationStatus";
+
+    /** @hide */
+    @IntDef(prefix = { "ACTIVITY_" }, value = {
+            ACTIVITY_OTHER,
+            ACTIVITY_BIRTHDAY,
+            ACTIVITY_ANNIVERSARY,
+            ACTIVITY_NEW_STORY,
+            ACTIVITY_MEDIA,
+            ACTIVITY_GAME,
+            ACTIVITY_LOCATION,
+            ACTIVITY_UPCOMING_BIRTHDAY
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ActivityType {}
+
+    public static final int ACTIVITY_OTHER = 0;
+    public static final int ACTIVITY_BIRTHDAY = 1;
+    public static final int ACTIVITY_ANNIVERSARY = 2;
+    public static final int ACTIVITY_NEW_STORY = 3;
+    public static final int ACTIVITY_MEDIA = 4;
+    public static final int ACTIVITY_GAME = 5;
+    public static final int ACTIVITY_LOCATION = 6;
+    public static final int ACTIVITY_UPCOMING_BIRTHDAY = 7;
+
+    /** @hide */
+    @IntDef(prefix = { "AVAILABILITY_" }, value = {
+            AVAILABILITY_UNKNOWN,
+            AVAILABILITY_AVAILABLE,
+            AVAILABILITY_BUSY,
+            AVAILABILITY_OFFLINE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Availability {}
+
+    public static final int AVAILABILITY_UNKNOWN = -1;
+    public static final int AVAILABILITY_AVAILABLE = 0;
+    public static final int AVAILABILITY_BUSY = 1;
+    public static final int AVAILABILITY_OFFLINE = 2;
+
+    private final String mId;
+    private final int mActivity;
+
+    private int mAvailability;
+    private CharSequence mDescription;
+    private Icon mIcon;
+    private long mStartTimeMs;
+    private long mEndTimeMs;
+
+    private ConversationStatus(Builder b) {
+        mId = b.mId;
+        mActivity = b.mActivity;
+        mAvailability = b.mAvailability;
+        mDescription = b.mDescription;
+        mIcon = b.mIcon;
+        mStartTimeMs = b.mStartTimeMs;
+        mEndTimeMs = b.mEndTimeMs;
+    }
+
+    private ConversationStatus(Parcel p) {
+        mId = p.readString();
+        mActivity = p.readInt();
+        mAvailability = p.readInt();
+        mDescription = p.readCharSequence();
+        mIcon = p.readParcelable(Icon.class.getClassLoader());
+        mStartTimeMs = p.readLong();
+        mEndTimeMs = p.readLong();
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeString(mId);
+        dest.writeInt(mActivity);
+        dest.writeInt(mAvailability);
+        dest.writeCharSequence(mDescription);
+        dest.writeParcelable(mIcon, flags);
+        dest.writeLong(mStartTimeMs);
+        dest.writeLong(mEndTimeMs);
+    }
+
+    public @NonNull String getId() {
+        return mId;
+    }
+
+    public @ActivityType int getActivity() {
+        return mActivity;
+    }
+
+    public @Availability
+    int getAvailability() {
+        return mAvailability;
+    }
+
+    public @Nullable
+    CharSequence getDescription() {
+        return mDescription;
+    }
+
+    public @Nullable Icon getIcon() {
+        return mIcon;
+    }
+
+    public long getStartTimeMillis() {
+        return mStartTimeMs;
+    }
+
+    public long getEndTimeMillis() {
+        return mEndTimeMs;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        ConversationStatus that = (ConversationStatus) o;
+        return mActivity == that.mActivity &&
+                mAvailability == that.mAvailability &&
+                mStartTimeMs == that.mStartTimeMs &&
+                mEndTimeMs == that.mEndTimeMs &&
+                mId.equals(that.mId) &&
+                Objects.equals(mDescription, that.mDescription) &&
+                Objects.equals(mIcon, that.mIcon);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mId, mActivity, mAvailability, mDescription, mIcon, mStartTimeMs,
+                mEndTimeMs);
+    }
+
+    @Override
+    public String toString() {
+        return "ConversationStatus{" +
+                "mId='" + mId + '\'' +
+                ", mActivity=" + mActivity +
+                ", mAvailability=" + mAvailability +
+                ", mDescription=" + mDescription +
+                ", mIcon=" + mIcon +
+                ", mStartTimeMs=" + mStartTimeMs +
+                ", mEndTimeMs=" + mEndTimeMs +
+                '}';
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final @NonNull Creator<ConversationStatus> CREATOR
+            = new Creator<ConversationStatus>() {
+        public ConversationStatus createFromParcel(Parcel source) {
+            return new ConversationStatus(source);
+        }
+
+        public ConversationStatus[] newArray(int size) {
+            return new ConversationStatus[size];
+        }
+    };
+
+    public static final class Builder {
+        final String mId;
+        final int mActivity;
+        int mAvailability = AVAILABILITY_UNKNOWN;
+        CharSequence mDescription;
+        Icon mIcon;
+        long mStartTimeMs = -1;
+        long mEndTimeMs = -1;
+
+        /**
+         * Creates a new builder.
+         *
+         * @param id The unique id for this status
+         * @param activity The type of status
+         */
+        public Builder(@NonNull String id, @ActivityType @NonNull int activity) {
+            mId = id;
+            mActivity = activity;
+        }
+
+
+        public @NonNull Builder setAvailability(@Availability int availability) {
+            mAvailability = availability;
+            return this;
+        }
+
+        public @NonNull Builder setDescription(@Nullable CharSequence description) {
+            mDescription = description;
+            return this;
+        }
+
+        public @NonNull Builder setIcon(@Nullable Icon icon) {
+            mIcon = icon;
+            return this;
+        }
+
+        public @NonNull Builder setStartTimeMillis(long startTimeMs) {
+            mStartTimeMs = startTimeMs;
+            return this;
+        }
+
+        public @NonNull Builder setEndTimeMillis(long endTimeMs) {
+            mEndTimeMs = endTimeMs;
+            return this;
+        }
+
+        public @NonNull ConversationStatus build() {
+            return new ConversationStatus(this);
+        }
+    }
+}
diff --git a/core/java/android/app/people/IPeopleManager.aidl b/core/java/android/app/people/IPeopleManager.aidl
index c547ef1..0d12ed0 100644
--- a/core/java/android/app/people/IPeopleManager.aidl
+++ b/core/java/android/app/people/IPeopleManager.aidl
@@ -16,6 +16,7 @@
 
 package android.app.people;
 
+import android.app.people.ConversationStatus;
 import android.content.pm.ParceledListSlice;
 import android.net.Uri;
 import android.os.IBinder;
@@ -45,4 +46,9 @@
      * conversation can't be found or no interactions have been recorded, returns 0L.
      */
     long getLastInteraction(in String packageName, int userId, in String shortcutId);
+
+    void addOrUpdateStatus(in String packageName, int userId, in String conversationId, in ConversationStatus status);
+    void clearStatus(in String packageName, int userId, in String conversationId, in String statusId);
+    void clearStatuses(in String packageName, int userId, in String conversationId);
+    ParceledListSlice getStatuses(in String packageName, int userId, in String conversationId);
 }
diff --git a/core/java/android/app/people/PeopleManager.java b/core/java/android/app/people/PeopleManager.java
new file mode 100644
index 0000000..de7ba62
--- /dev/null
+++ b/core/java/android/app/people/PeopleManager.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.people;
+
+import android.annotation.NonNull;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.ShortcutInfo;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * This class allows interaction with conversation and people data.
+ */
+@SystemService(Context.PEOPLE_SERVICE)
+public final class PeopleManager {
+
+    private static final String LOG_TAG = PeopleManager.class.getSimpleName();
+
+    @NonNull
+    private final Context mContext;
+
+    @NonNull
+    private final IPeopleManager mService;
+
+    /**
+     * @hide
+     */
+    public PeopleManager(@NonNull Context context) throws ServiceManager.ServiceNotFoundException {
+        mContext = context;
+        mService = IPeopleManager.Stub.asInterface(ServiceManager.getServiceOrThrow(
+                Context.PEOPLE_SERVICE));
+    }
+
+
+    /**
+     * Sets or updates a {@link ConversationStatus} for a conversation.
+     *
+     * <p>Statuses are meant to represent current information about the conversation. Like
+     * notifications, they are transient and are not persisted beyond a reboot, nor are they
+     * backed up and restored.</p>
+     * <p>If the provided conversation shortcut is not already pinned, or cached by the system,
+     * it will remain cached as long as the status is active.</p>
+     *
+     * @param conversationId the {@link ShortcutInfo#getId() id} of the shortcut backing the
+     *                       conversation that has an active status
+     * @param status the current status for the given conversation
+     *
+     * @return whether the role is available in the system
+     */
+    public void addOrUpdateStatus(@NonNull String conversationId,
+            @NonNull ConversationStatus status) {
+        Preconditions.checkStringNotEmpty(conversationId);
+        Objects.requireNonNull(status);
+        try {
+            mService.addOrUpdateStatus(
+                    mContext.getPackageName(), mContext.getUserId(), conversationId, status);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Unpublishes a given status from the given conversation.
+     *
+     * @param conversationId the {@link ShortcutInfo#getId() id} of the shortcut backing the
+     *                       conversation that has an active status
+     * @param statusId the {@link ConversationStatus#getId() id} of a published status for the given
+     *                 conversation
+     */
+    public void clearStatus(@NonNull String conversationId, @NonNull String statusId) {
+        Preconditions.checkStringNotEmpty(conversationId);
+        Preconditions.checkStringNotEmpty(statusId);
+        try {
+            mService.clearStatus(
+                    mContext.getPackageName(), mContext.getUserId(), conversationId, statusId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Removes all published statuses for the given conversation.
+     *
+     * @param conversationId the {@link ShortcutInfo#getId() id} of the shortcut backing the
+     *                       conversation that has one or more active statuses
+     */
+    public void clearStatuses(@NonNull String conversationId) {
+        Preconditions.checkStringNotEmpty(conversationId);
+        try {
+            mService.clearStatuses(
+                    mContext.getPackageName(), mContext.getUserId(), conversationId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns all of the currently published statuses for a given conversation.
+     *
+     * @param conversationId the {@link ShortcutInfo#getId() id} of the shortcut backing the
+     *                       conversation that has one or more active statuses
+     */
+    public @NonNull List<ConversationStatus> getStatuses(@NonNull String conversationId) {
+        try {
+            final ParceledListSlice<ConversationStatus> parceledList
+                    = mService.getStatuses(
+                            mContext.getPackageName(), mContext.getUserId(), conversationId);
+            if (parceledList != null) {
+                return parceledList.getList();
+            }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+        return new ArrayList<>();
+    }
+}
diff --git a/core/java/android/app/role/RoleControllerManager.java b/core/java/android/app/role/RoleControllerManager.java
index ba1f612..8dde2c5 100644
--- a/core/java/android/app/role/RoleControllerManager.java
+++ b/core/java/android/app/role/RoleControllerManager.java
@@ -20,6 +20,8 @@
 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;
@@ -46,6 +48,8 @@
  *
  * @hide
  */
+@SystemService(Context.ROLE_CONTROLLER_SERVICE)
+@TestApi
 public class RoleControllerManager {
 
     private static final String LOG_TAG = RoleControllerManager.class.getSimpleName();
@@ -195,11 +199,32 @@
     }
 
     /**
+     * @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 -> {
@@ -217,6 +242,7 @@
      * @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 9ddd5be..8b2e07b 100644
--- a/core/java/android/app/role/RoleManager.java
+++ b/core/java/android/app/role/RoleManager.java
@@ -174,9 +174,6 @@
     @NonNull
     private final Object mListenersLock = new Object();
 
-    @NonNull
-    private final RoleControllerManager mRoleControllerManager;
-
     /**
      * @hide
      */
@@ -184,7 +181,6 @@
         mContext = context;
         mService = IRoleManager.Stub.asInterface(ServiceManager.getServiceOrThrow(
                 Context.ROLE_SERVICE));
-        mRoleControllerManager = new RoleControllerManager(context);
     }
 
     /**
@@ -680,44 +676,6 @@
         }
     }
 
-    /**
-     * 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)
-    @SystemApi
-    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)
-    @SystemApi
-    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/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 7a6ff79..381318b 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -824,6 +824,25 @@
      * error
      */
     private boolean registerApp(BluetoothGattCallback callback, Handler handler) {
+        return registerApp(callback, handler, false);
+    }
+
+    /**
+     * Register an application callback to start using GATT.
+     *
+     * <p>This is an asynchronous call. The callback {@link BluetoothGattCallback#onAppRegistered}
+     * is used to notify success or failure if the function returns true.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param callback GATT callback handler that will receive asynchronous callbacks.
+     * @param eatt_support indicate to allow for eatt support
+     * @return If true, the callback will be called to notify success or failure, false on immediate
+     * error
+     * @hide
+     */
+    private boolean registerApp(BluetoothGattCallback callback, Handler handler,
+                                boolean eatt_support) {
         if (DBG) Log.d(TAG, "registerApp()");
         if (mService == null) return false;
 
@@ -833,7 +852,7 @@
         if (DBG) Log.d(TAG, "registerApp() - UUID=" + uuid);
 
         try {
-            mService.registerClient(new ParcelUuid(uuid), mBluetoothGattCallback);
+            mService.registerClient(new ParcelUuid(uuid), mBluetoothGattCallback, eatt_support);
         } catch (RemoteException e) {
             Log.e(TAG, "", e);
             return false;
diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java
index 13b1b4f..088b016 100644
--- a/core/java/android/bluetooth/BluetoothGattServer.java
+++ b/core/java/android/bluetooth/BluetoothGattServer.java
@@ -443,6 +443,25 @@
      * error
      */
     /*package*/ boolean registerCallback(BluetoothGattServerCallback callback) {
+        return registerCallback(callback, false);
+    }
+
+    /**
+     * Register an application callback to start using GattServer.
+     *
+     * <p>This is an asynchronous call. The callback is used to notify
+     * success or failure if the function returns true.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param callback GATT callback handler that will receive asynchronous callbacks.
+     * @param eatt_support indicates if server can use eatt
+     * @return true, the callback will be called to notify success or failure, false on immediate
+     * error
+     * @hide
+     */
+    /*package*/ boolean registerCallback(BluetoothGattServerCallback callback,
+                                         boolean eatt_support) {
         if (DBG) Log.d(TAG, "registerCallback()");
         if (mService == null) {
             Log.e(TAG, "GATT service not available");
@@ -459,7 +478,7 @@
 
             mCallback = callback;
             try {
-                mService.registerServer(new ParcelUuid(uuid), mBluetoothGattServerCallback);
+                mService.registerServer(new ParcelUuid(uuid), mBluetoothGattServerCallback, eatt_support);
             } catch (RemoteException e) {
                 Log.e(TAG, "", e);
                 mCallback = null;
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
index 3b4fe0a..d5c1c3e 100644
--- a/core/java/android/bluetooth/BluetoothManager.java
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -225,6 +225,24 @@
      *
      * @param context App context
      * @param callback GATT server callback handler that will receive asynchronous callbacks.
+     * @param eatt_support idicates if server should use eatt channel for notifications.
+     * @return BluetoothGattServer instance
+     * @hide
+     */
+    public BluetoothGattServer openGattServer(Context context,
+            BluetoothGattServerCallback callback, boolean eatt_support) {
+        return (openGattServer(context, callback, BluetoothDevice.TRANSPORT_AUTO, eatt_support));
+    }
+
+    /**
+     * Open a GATT Server
+     * The callback is used to deliver results to Caller, such as connection status as well
+     * as the results of any other GATT server operations.
+     * The method returns a BluetoothGattServer instance. You can use BluetoothGattServer
+     * to conduct GATT server operations.
+     *
+     * @param context App context
+     * @param callback GATT server callback handler that will receive asynchronous callbacks.
      * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
      * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
      * BluetoothDevice#TRANSPORT_LE}
@@ -233,6 +251,27 @@
      */
     public BluetoothGattServer openGattServer(Context context,
             BluetoothGattServerCallback callback, int transport) {
+        return (openGattServer(context, callback, transport, false));
+    }
+
+    /**
+     * Open a GATT Server
+     * The callback is used to deliver results to Caller, such as connection status as well
+     * as the results of any other GATT server operations.
+     * The method returns a BluetoothGattServer instance. You can use BluetoothGattServer
+     * to conduct GATT server operations.
+     *
+     * @param context App context
+     * @param callback GATT server callback handler that will receive asynchronous callbacks.
+     * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
+     * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
+     * BluetoothDevice#TRANSPORT_LE}
+     * @param eatt_support idicates if server should use eatt channel for notifications.
+     * @return BluetoothGattServer instance
+     * @hide
+     */
+    public BluetoothGattServer openGattServer(Context context,
+            BluetoothGattServerCallback callback, int transport, boolean eatt_support) {
         if (context == null || callback == null) {
             throw new IllegalArgumentException("null parameter: " + context + " " + callback);
         }
@@ -248,7 +287,7 @@
                 return null;
             }
             BluetoothGattServer mGattServer = new BluetoothGattServer(iGatt, transport);
-            Boolean regStatus = mGattServer.registerCallback(callback);
+            Boolean regStatus = mGattServer.registerCallback(callback, eatt_support);
             return regStatus ? mGattServer : null;
         } catch (RemoteException e) {
             Log.e(TAG, "", e);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 33f9607..5ccceca 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -40,6 +40,7 @@
 import android.app.IApplicationThread;
 import android.app.IServiceConnection;
 import android.app.VrManager;
+import android.app.people.PeopleManager;
 import android.app.time.TimeManager;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ApplicationInfo;
@@ -4508,6 +4509,17 @@
     public static final String CONTENT_CAPTURE_MANAGER_SERVICE = "content_capture";
 
     /**
+     * Official published name of the translation service.
+     *
+     * @hide
+     * @see #getSystemService(String)
+     */
+    // TODO(b/176208267): change it back to translation before S release.
+    @SystemApi
+    @SuppressLint("ServiceName")
+    public static final String TRANSLATION_MANAGER_SERVICE = "transformer";
+
+    /**
      * Used for getting content selections and classifications for task snapshots.
      *
      * @hide
@@ -4821,6 +4833,16 @@
     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.
@@ -5301,10 +5323,10 @@
     public static final String SMS_SERVICE = "sms";
 
     /**
-     * Use with {@link #getSystemService(String)} to access people service.
+     * Use with {@link #getSystemService(String)} to access a {@link PeopleManager} to interact
+     * with your published conversations.
      *
      * @see #getSystemService(String)
-     * @hide
      */
     public static final String PEOPLE_SERVICE = "people";
 
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index e074eab..17c4d25 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3406,6 +3406,14 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+     * The device supports translation of text-to-text in multiple languages via integration with
+     * the system {@link android.service.translation.TranslationService translation provider}.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_TRANSLATION = "android.software.translation";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
      * The device implements headtracking suitable for a VR device.
      */
     @SdkConstant(SdkConstantType.FEATURE)
diff --git a/core/java/android/hardware/SensorPrivacyManager.java b/core/java/android/hardware/SensorPrivacyManager.java
index b3b2dd8..8497525 100644
--- a/core/java/android/hardware/SensorPrivacyManager.java
+++ b/core/java/android/hardware/SensorPrivacyManager.java
@@ -20,7 +20,6 @@
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemService;
-import android.annotation.UserIdInt;
 import android.content.Context;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -164,12 +163,11 @@
      * Registers a new listener to receive notification when the state of sensor privacy
      * changes.
      *
-     * @param userId the user's id
      * @param sensor the sensor to listen to changes to
      * @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor
      *                 privacy changes.
      */
-    public void addSensorPrivacyListener(@UserIdInt int userId, @IndividualSensor int sensor,
+    public void addSensorPrivacyListener(@IndividualSensor int sensor,
             final OnSensorPrivacyChangedListener listener) {
         synchronized (mListeners) {
             ISensorPrivacyListener iListener = mListeners.get(listener);
@@ -184,7 +182,8 @@
             }
 
             try {
-                mService.addIndividualSensorPrivacyListener(userId, sensor, iListener);
+                mService.addIndividualSensorPrivacyListener(mContext.getUserId(), sensor,
+                        iListener);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -230,10 +229,9 @@
      *
      * @return true if sensor privacy is currently enabled, false otherwise.
      */
-    public boolean isIndividualSensorPrivacyEnabled(@UserIdInt int userId,
-            @IndividualSensor int sensor) {
+    public boolean isIndividualSensorPrivacyEnabled(@IndividualSensor int sensor) {
         try {
-            return mService.isIndividualSensorPrivacyEnabled(userId, sensor);
+            return mService.isIndividualSensorPrivacyEnabled(mContext.getUserId(), sensor);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -242,13 +240,14 @@
     /**
      * Sets sensor privacy to the specified state for an individual sensor.
      *
+     * @param sensor the sensor which to change the state for
      * @param enable the state to which sensor privacy should be set.
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY)
-    public void setIndividualSensorPrivacy(@UserIdInt int userId, @IndividualSensor int sensor,
+    public void setIndividualSensorPrivacy(@IndividualSensor int sensor,
             boolean enable) {
         try {
-            mService.setIndividualSensorPrivacy(userId, sensor, enable);
+            mService.setIndividualSensorPrivacy(mContext.getUserId(), sensor, enable);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -256,15 +255,17 @@
 
     /**
      * Sets sensor privacy to the specified state for an individual sensor for the profile group of
-     * the given user.
+     * context's user.
      *
+     * @param sensor the sensor which to change the state for
      * @param enable the state to which sensor privacy should be set.
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY)
-    public void setIndividualSensorPrivacyForProfileGroup(@UserIdInt int userId,
-            @IndividualSensor int sensor, boolean enable) {
+    public void setIndividualSensorPrivacyForProfileGroup(@IndividualSensor int sensor,
+            boolean enable) {
         try {
-            mService.setIndividualSensorPrivacyForProfileGroup(userId, sensor, enable);
+            mService.setIndividualSensorPrivacyForProfileGroup(mContext.getUserId(), sensor,
+                    enable);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/hardware/face/OWNERS b/core/java/android/hardware/face/OWNERS
index 33527f8..be10df1 100644
--- a/core/java/android/hardware/face/OWNERS
+++ b/core/java/android/hardware/face/OWNERS
@@ -1,3 +1,7 @@
 # Bug component: 879035
 
+curtislb@google.com
+ilyamaty@google.com
 jaggies@google.com
+joshmccloskey@google.com
+kchyn@google.com
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 36348b3..8bfbad6 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -442,6 +442,24 @@
     }
 
     /**
+     * Check that networking is blocked for the given uid.
+     *
+     * @param uid The target uid.
+     * @param meteredNetwork True if the network is metered.
+     * @return true if networking is blocked for the given uid according to current networking
+     *         policies.
+     *
+     * @hide
+     */
+    public boolean isUidNetworkingBlocked(int uid, boolean meteredNetwork) {
+        try {
+            return mService.isUidNetworkingBlocked(uid, meteredNetwork);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Get multipath preference for the given network.
      */
     public int getMultipathPreference(Network network) {
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 6209718..66b99b9 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -40,6 +40,18 @@
  */
 public class NetworkRequest implements Parcelable {
     /**
+     * The first requestId value that will be allocated.
+     * @hide only used by ConnectivityService.
+     */
+    public static final int FIRST_REQUEST_ID = 1;
+
+    /**
+     * The requestId value that represents the absence of a request.
+     * @hide only used by ConnectivityService.
+     */
+    public static final int REQUEST_ID_NONE = -1;
+
+    /**
      * The {@link NetworkCapabilities} that define this request.
      * @hide
      */
diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java
index bf8ac6e..ba29a15a 100644
--- a/core/java/android/os/BatteryConsumer.java
+++ b/core/java/android/os/BatteryConsumer.java
@@ -39,6 +39,11 @@
             POWER_COMPONENT_USAGE,
             POWER_COMPONENT_CPU,
             POWER_COMPONENT_BLUETOOTH,
+            POWER_COMPONENT_CAMERA,
+            POWER_COMPONENT_AUDIO,
+            POWER_COMPONENT_VIDEO,
+            POWER_COMPONENT_FLASHLIGHT,
+            POWER_COMPONENT_SYSTEM_SERVICES,
     })
     @Retention(RetentionPolicy.SOURCE)
     public static @interface PowerComponent {
@@ -47,8 +52,13 @@
     public static final int POWER_COMPONENT_USAGE = 0;
     public static final int POWER_COMPONENT_CPU = 1;
     public static final int POWER_COMPONENT_BLUETOOTH = 2;
+    public static final int POWER_COMPONENT_CAMERA = 3;
+    public static final int POWER_COMPONENT_AUDIO = 4;
+    public static final int POWER_COMPONENT_VIDEO = 5;
+    public static final int POWER_COMPONENT_FLASHLIGHT = 6;
+    public static final int POWER_COMPONENT_SYSTEM_SERVICES = 7;
 
-    public static final int POWER_COMPONENT_COUNT = 3;
+    public static final int POWER_COMPONENT_COUNT = 8;
 
     public static final int FIRST_CUSTOM_POWER_COMPONENT_ID = 1000;
     public static final int LAST_CUSTOM_POWER_COMPONENT_ID = 9999;
@@ -75,6 +85,8 @@
             TIME_COMPONENT_CPU,
             TIME_COMPONENT_CPU_FOREGROUND,
             TIME_COMPONENT_BLUETOOTH,
+            TIME_COMPONENT_CAMERA,
+            TIME_COMPONENT_FLASHLIGHT,
     })
     @Retention(RetentionPolicy.SOURCE)
     public static @interface TimeComponent {
@@ -84,8 +96,12 @@
     public static final int TIME_COMPONENT_CPU = 1;
     public static final int TIME_COMPONENT_CPU_FOREGROUND = 2;
     public static final int TIME_COMPONENT_BLUETOOTH = 3;
+    public static final int TIME_COMPONENT_CAMERA = 4;
+    public static final int TIME_COMPONENT_AUDIO = 5;
+    public static final int TIME_COMPONENT_VIDEO = 6;
+    public static final int TIME_COMPONENT_FLASHLIGHT = 7;
 
-    public static final int TIME_COMPONENT_COUNT = 4;
+    public static final int TIME_COMPONENT_COUNT = 8;
 
     public static final int FIRST_CUSTOM_TIME_COMPONENT_ID = 1000;
     public static final int LAST_CUSTOM_TIME_COMPONENT_ID = 9999;
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index b57418d..c0b2ada 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -1071,6 +1071,7 @@
                 PRIMITIVE_SLOW_RISE,
                 PRIMITIVE_QUICK_FALL,
                 PRIMITIVE_TICK,
+                PRIMITIVE_LOW_TICK,
         })
         @Retention(RetentionPolicy.SOURCE)
         public @interface Primitive {}
@@ -1116,6 +1117,12 @@
          */
         // Internally this maps to the HAL constant CompositePrimitive::LIGHT_TICK
         public static final int PRIMITIVE_TICK = 7;
+        /**
+         * This very short low frequency effect should produce a light crisp sensation
+         * intended to be used repetitively for dynamic feedback.
+         */
+        // Internally this maps to the HAL constant CompositePrimitive::LOW_TICK
+        public static final int PRIMITIVE_LOW_TICK = 8;
 
 
         private ArrayList<PrimitiveEffect> mEffects = new ArrayList<>();
@@ -1194,7 +1201,7 @@
          *
          */
         static int checkPrimitive(int primitiveId) {
-            Preconditions.checkArgumentInRange(primitiveId, PRIMITIVE_NOOP, PRIMITIVE_TICK,
+            Preconditions.checkArgumentInRange(primitiveId, PRIMITIVE_NOOP, PRIMITIVE_LOW_TICK,
                     "primitiveId");
             return primitiveId;
         }
@@ -1223,6 +1230,8 @@
                     return "PRIMITIVE_QUICK_FALL";
                 case PRIMITIVE_TICK:
                     return "PRIMITIVE_TICK";
+                case PRIMITIVE_LOW_TICK:
+                    return "PRIMITIVE_LOW_TICK";
                 default:
                     return Integer.toString(id);
             }
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 8ac1fc1..b5abe2a 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -163,7 +163,7 @@
         mMaxFileSize = in.readLong();
         mOwner = in.readParcelable(null);
         if (in.readInt() != 0) {
-            mUuid = StorageManager.convert(in.readString());
+            mUuid = StorageManager.convert(in.readString8());
         } else {
             mUuid = null;
         }
diff --git a/core/java/android/permission/PermGroupUsage.java b/core/java/android/permission/PermGroupUsage.java
index 3bee401..7335e00 100644
--- a/core/java/android/permission/PermGroupUsage.java
+++ b/core/java/android/permission/PermGroupUsage.java
@@ -30,17 +30,19 @@
 
     private final String mPackageName;
     private final int mUid;
+    private final long mLastAccess;
     private final String mPermGroupName;
     private final boolean mIsActive;
     private final boolean mIsPhoneCall;
     private final CharSequence mAttribution;
 
     PermGroupUsage(@NonNull String packageName, int uid,
-            @NonNull String permGroupName, boolean isActive, boolean isPhoneCall,
+            @NonNull String permGroupName, long lastAccess, boolean isActive, boolean isPhoneCall,
             @Nullable CharSequence attribution) {
         this.mPackageName = packageName;
         this.mUid = uid;
         this.mPermGroupName = permGroupName;
+        this.mLastAccess = lastAccess;
         this.mIsActive = isActive;
         this.mIsPhoneCall = isPhoneCall;
         this.mAttribution = attribution;
@@ -58,6 +60,10 @@
         return mPermGroupName;
     }
 
+    public long getLastAccess() {
+        return mLastAccess;
+    }
+
     public boolean isActive() {
         return mIsActive;
     }
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index 4868827..00ba867 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -187,7 +187,7 @@
             for (int usageNum = 0; usageNum < numUsages; usageNum++) {
                 OpUsage usage = rawUsages.get(permGroup).get(usageNum);
                 usages.add(new PermGroupUsage(usage.packageName, usage.uid, permGroup,
-                        usage.isRunning, isPhone,
+                        usage.lastAccessTime, usage.isRunning, isPhone,
                         packagesWithAttributionLabels.get(usage.toPackageAttr())));
             }
         }
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index ec4d81c..7a856e8 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -101,6 +101,13 @@
     public static final String NAMESPACE_APP_COMPAT = "app_compat";
 
     /**
+     * Namespace for all app hibernation related features.
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_APP_HIBERNATION = "app_hibernation";
+
+    /**
      * Namespace for app standby configurations.
      *
      * @hide
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 69ca28a..9db7ca0 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -14630,6 +14630,34 @@
         public static final String BACKPORT_S_NOTIF_RULES = "backport_s_notif_rules";
 
         /**
+         * The decoration to put on fully custom views that target S.
+         *
+         * <p>Values are:
+         * <br>0: DECORATION_NONE: no decorations.
+         * <br>1: DECORATION_MINIMAL: most minimal template; just the icon and the expander.
+         * <br>2: DECORATION_PARTIAL: basic template without the top line.
+         * <br>3: DECORATION_FULL_COMPATIBLE: basic template with the top line; 40dp of height.
+         * <br>4: DECORATION_FULL_CONSTRAINED: basic template with the top line;  28dp of height.
+         * <p>See {@link android.app.Notification.DevFlags} for more details.
+         * @hide
+         */
+        public static final String FULLY_CUSTOM_VIEW_NOTIF_DECORATION =
+                "fully_custom_view_notif_decoration";
+
+        /**
+         * The decoration to put on decorated custom views that target S.
+         *
+         * <p>Values are:
+         * <br>2: DECORATION_PARTIAL: basic template without the top line.
+         * <br>3: DECORATION_FULL_COMPATIBLE: basic template with the top line; 40dp of height.
+         * <br>4: DECORATION_FULL_CONSTRAINED: basic template with the top line;  28dp of height.
+         * <p>See {@link android.app.Notification.DevFlags} for more details.
+         * @hide
+         */
+        public static final String DECORATED_CUSTOM_VIEW_NOTIF_DECORATION =
+                "decorated_custom_view_notif_decoration";
+
+        /**
          * Block untrusted touches mode.
          *
          * Can be one of:
diff --git a/core/java/android/service/translation/ITranslationCallback.aidl b/core/java/android/service/translation/ITranslationCallback.aidl
new file mode 100644
index 0000000..333cb57
--- /dev/null
+++ b/core/java/android/service/translation/ITranslationCallback.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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.service.translation;
+
+import android.view.translation.TranslationResponse;
+
+/**
+ * Interface to receive the result of a {@code TranslationRequest}.
+ *
+ * @hide
+ */
+oneway interface ITranslationCallback {
+    void onTranslationComplete(in TranslationResponse translationResponse);
+    void onError();
+}
diff --git a/core/java/android/service/translation/ITranslationService.aidl b/core/java/android/service/translation/ITranslationService.aidl
new file mode 100644
index 0000000..6d6f278
--- /dev/null
+++ b/core/java/android/service/translation/ITranslationService.aidl
@@ -0,0 +1,38 @@
+/*
+ * 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.service.translation;
+
+import android.service.translation.TranslationRequest;
+import android.service.translation.ITranslationCallback;
+import android.view.translation.TranslationSpec;
+import com.android.internal.os.IResultReceiver;
+
+/**
+ * System-wide on-device translation service.
+ *
+ * <p>Services requests to translate text between different languages. The primary use case for this
+ * service is automatic translation of text and web views, when the auto Translate feature is
+ * enabled.
+ *
+ * @hide
+ */
+oneway interface ITranslationService {
+    void onConnected();
+    void onDisconnected();
+    void onCreateTranslationSession(in TranslationSpec sourceSpec, in TranslationSpec destSpec,
+         int sessionId, in IResultReceiver receiver);
+}
diff --git a/core/java/android/service/translation/OWNERS b/core/java/android/service/translation/OWNERS
new file mode 100644
index 0000000..a1e663a
--- /dev/null
+++ b/core/java/android/service/translation/OWNERS
@@ -0,0 +1,8 @@
+# Bug component: 994311
+
+adamhe@google.com
+augale@google.com
+joannechung@google.com
+lpeter@google.com
+svetoslavganov@google.com
+tymtsai@google.com
diff --git a/core/java/android/service/translation/OnTranslationResultCallbackWrapper.java b/core/java/android/service/translation/OnTranslationResultCallbackWrapper.java
new file mode 100644
index 0000000..345c69c
--- /dev/null
+++ b/core/java/android/service/translation/OnTranslationResultCallbackWrapper.java
@@ -0,0 +1,92 @@
+/*
+ * 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.service.translation;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.DeadObjectException;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.translation.TranslationResponse;
+
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Callback to receive the {@link TranslationResponse} on successful translation.
+ *
+ * @hide
+ */
+final class OnTranslationResultCallbackWrapper implements
+        TranslationService.OnTranslationResultCallback {
+
+    private static final String TAG = "OnTranslationResultCallback";
+
+    private final @NonNull ITranslationCallback mCallback;
+
+    private AtomicBoolean mCalled;
+
+    /**
+     * @hide
+     */
+    public OnTranslationResultCallbackWrapper(@NonNull ITranslationCallback callback) {
+        mCallback = Objects.requireNonNull(callback);
+        mCalled = new AtomicBoolean();
+    }
+
+    @Override
+    public void onTranslationSuccess(@Nullable TranslationResponse response) {
+        assertNotCalled();
+        if (mCalled.getAndSet(true)) {
+            throw new IllegalStateException("Already called");
+        }
+
+        try {
+            mCallback.onTranslationComplete(response);
+        } catch (RemoteException e) {
+            if (e instanceof DeadObjectException) {
+                Log.w(TAG, "Process is dead, ignore.");
+                return;
+            }
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    @Override
+    public void onError() {
+        assertNotCalled();
+        if (mCalled.getAndSet(true)) {
+            throw new IllegalStateException("Already called");
+        }
+
+        try {
+            mCallback.onError();
+        } catch (RemoteException e) {
+            if (e instanceof DeadObjectException) {
+                Log.w(TAG, "Process is dead, ignore.");
+                return;
+            }
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    private void assertNotCalled() {
+        if (mCalled.get()) {
+            throw new IllegalStateException("Already called");
+        }
+    }
+}
diff --git a/core/java/android/service/translation/TranslationRequest.aidl b/core/java/android/service/translation/TranslationRequest.aidl
new file mode 100644
index 0000000..9a2d415
--- /dev/null
+++ b/core/java/android/service/translation/TranslationRequest.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.service.translation;
+
+parcelable TranslationRequest;
diff --git a/core/java/android/service/translation/TranslationRequest.java b/core/java/android/service/translation/TranslationRequest.java
new file mode 100644
index 0000000..b8afd70
--- /dev/null
+++ b/core/java/android/service/translation/TranslationRequest.java
@@ -0,0 +1,281 @@
+/*
+ * 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.service.translation;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.view.translation.TranslationSpec;
+
+import com.android.internal.util.DataClass;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Internal translation request sent to the {@link android.service.translation.TranslationService}
+ * which contains the text to be translated.
+ *
+ * @hide
+ */
+@SystemApi
+@DataClass(genConstructor = true, genBuilder = true, genToString = true)
+public final class TranslationRequest implements Parcelable {
+
+    private final int mRequestId;
+    @NonNull
+    private final TranslationSpec mSourceSpec;
+    @NonNull
+    private final TranslationSpec mDestSpec;
+    @NonNull
+    private final List<android.view.translation.TranslationRequest> mTranslationRequests;
+
+
+
+    // Code below generated by codegen v1.0.22.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/translation/TranslationRequest.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    @DataClass.Generated.Member
+    public TranslationRequest(
+            int requestId,
+            @NonNull TranslationSpec sourceSpec,
+            @NonNull TranslationSpec destSpec,
+            @NonNull List<android.view.translation.TranslationRequest> translationRequests) {
+        this.mRequestId = requestId;
+        this.mSourceSpec = sourceSpec;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mSourceSpec);
+        this.mDestSpec = destSpec;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mDestSpec);
+        this.mTranslationRequests = translationRequests;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mTranslationRequests);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public int getRequestId() {
+        return mRequestId;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull TranslationSpec getSourceSpec() {
+        return mSourceSpec;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull TranslationSpec getDestSpec() {
+        return mDestSpec;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull List<android.view.translation.TranslationRequest> getTranslationRequests() {
+        return mTranslationRequests;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "TranslationRequest { " +
+                "requestId = " + mRequestId + ", " +
+                "sourceSpec = " + mSourceSpec + ", " +
+                "destSpec = " + mDestSpec + ", " +
+                "translationRequests = " + mTranslationRequests +
+        " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeInt(mRequestId);
+        dest.writeTypedObject(mSourceSpec, flags);
+        dest.writeTypedObject(mDestSpec, flags);
+        dest.writeParcelableList(mTranslationRequests, flags);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ TranslationRequest(@NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        int requestId = in.readInt();
+        TranslationSpec sourceSpec = (TranslationSpec) in.readTypedObject(TranslationSpec.CREATOR);
+        TranslationSpec destSpec = (TranslationSpec) in.readTypedObject(TranslationSpec.CREATOR);
+        List<android.view.translation.TranslationRequest> translationRequests = new ArrayList<>();
+        in.readParcelableList(translationRequests, android.view.translation.TranslationRequest.class.getClassLoader());
+
+        this.mRequestId = requestId;
+        this.mSourceSpec = sourceSpec;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mSourceSpec);
+        this.mDestSpec = destSpec;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mDestSpec);
+        this.mTranslationRequests = translationRequests;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mTranslationRequests);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<TranslationRequest> CREATOR
+            = new Parcelable.Creator<TranslationRequest>() {
+        @Override
+        public TranslationRequest[] newArray(int size) {
+            return new TranslationRequest[size];
+        }
+
+        @Override
+        public TranslationRequest createFromParcel(@NonNull Parcel in) {
+            return new TranslationRequest(in);
+        }
+    };
+
+    /**
+     * A builder for {@link TranslationRequest}
+     */
+    @SuppressWarnings("WeakerAccess")
+    @DataClass.Generated.Member
+    public static final class Builder {
+
+        private int mRequestId;
+        private @NonNull TranslationSpec mSourceSpec;
+        private @NonNull TranslationSpec mDestSpec;
+        private @NonNull List<android.view.translation.TranslationRequest> mTranslationRequests;
+
+        private long mBuilderFieldsSet = 0L;
+
+        public Builder(
+                int requestId,
+                @NonNull TranslationSpec sourceSpec,
+                @NonNull TranslationSpec destSpec,
+                @NonNull List<android.view.translation.TranslationRequest> translationRequests) {
+            mRequestId = requestId;
+            mSourceSpec = sourceSpec;
+            com.android.internal.util.AnnotationValidations.validate(
+                    NonNull.class, null, mSourceSpec);
+            mDestSpec = destSpec;
+            com.android.internal.util.AnnotationValidations.validate(
+                    NonNull.class, null, mDestSpec);
+            mTranslationRequests = translationRequests;
+            com.android.internal.util.AnnotationValidations.validate(
+                    NonNull.class, null, mTranslationRequests);
+        }
+
+        @DataClass.Generated.Member
+        public @NonNull Builder setRequestId(int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x1;
+            mRequestId = value;
+            return this;
+        }
+
+        @DataClass.Generated.Member
+        public @NonNull Builder setSourceSpec(@NonNull TranslationSpec value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x2;
+            mSourceSpec = value;
+            return this;
+        }
+
+        @DataClass.Generated.Member
+        public @NonNull Builder setDestSpec(@NonNull TranslationSpec value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x4;
+            mDestSpec = value;
+            return this;
+        }
+
+        @DataClass.Generated.Member
+        public @NonNull Builder setTranslationRequests(@NonNull List<android.view.translation.TranslationRequest> value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x8;
+            mTranslationRequests = value;
+            return this;
+        }
+
+        /** @see #setTranslationRequests */
+        @DataClass.Generated.Member
+        public @NonNull Builder addTranslationRequests(@NonNull android.view.translation.TranslationRequest value) {
+            // You can refine this method's name by providing item's singular name, e.g.:
+            // @DataClass.PluralOf("item")) mItems = ...
+
+            if (mTranslationRequests == null) setTranslationRequests(new ArrayList<>());
+            mTranslationRequests.add(value);
+            return this;
+        }
+
+        /** Builds the instance. This builder should not be touched after calling this! */
+        public @NonNull TranslationRequest build() {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x10; // Mark builder used
+
+            TranslationRequest o = new TranslationRequest(
+                    mRequestId,
+                    mSourceSpec,
+                    mDestSpec,
+                    mTranslationRequests);
+            return o;
+        }
+
+        private void checkNotUsed() {
+            if ((mBuilderFieldsSet & 0x10) != 0) {
+                throw new IllegalStateException(
+                        "This Builder should not be reused. Use a new Builder instance instead");
+            }
+        }
+    }
+
+    @DataClass.Generated(
+            time = 1609966181888L,
+            codegenVersion = "1.0.22",
+            sourceFile = "frameworks/base/core/java/android/service/translation/TranslationRequest.java",
+            inputSignatures = "private final  int mRequestId\nprivate final @android.annotation.NonNull android.view.translation.TranslationSpec mSourceSpec\nprivate final @android.annotation.NonNull android.view.translation.TranslationSpec mDestSpec\nprivate final @android.annotation.NonNull java.util.List<android.view.translation.TranslationRequest> mTranslationRequests\nclass TranslationRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=true, genBuilder=true, genToString=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/service/translation/TranslationService.java b/core/java/android/service/translation/TranslationService.java
new file mode 100644
index 0000000..b028807
--- /dev/null
+++ b/core/java/android/service/translation/TranslationService.java
@@ -0,0 +1,261 @@
+/*
+ * 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.service.translation;
+
+import static android.view.translation.Translator.EXTRA_SERVICE_BINDER;
+import static android.view.translation.Translator.EXTRA_SESSION_ID;
+
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
+import android.annotation.CallSuper;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.Intent;
+import android.os.BaseBundle;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.translation.ITranslationDirectManager;
+import android.view.translation.TranslationManager;
+import android.view.translation.TranslationResponse;
+import android.view.translation.TranslationSpec;
+
+import com.android.internal.os.IResultReceiver;
+import com.android.internal.util.SyncResultReceiver;
+
+/**
+ * Service for translating text.
+ * @hide
+ */
+@SystemApi
+public abstract class TranslationService extends Service {
+    private static final String TAG = "TranslationService";
+
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     *
+     * <p>To be supported, the service must also require the
+     * {@link android.Manifest.permission#BIND_TRANSLATION_SERVICE} permission so
+     * that other applications can not abuse it.
+     */
+    public static final String SERVICE_INTERFACE =
+            "android.service.translation.TranslationService";
+
+    /**
+     * Name under which a TranslationService component publishes information about itself.
+     *
+     * <p>This meta-data should reference an XML resource containing a
+     * <code>&lt;{@link
+     * android.R.styleable#TranslationService translation-service}&gt;</code> tag.
+     *
+     * <p>Here's an example of how to use it on {@code AndroidManifest.xml}:
+     * TODO: fill in doc example (check CCService/AFService).
+     */
+    public static final String SERVICE_META_DATA = "android.translation_service";
+
+    private Handler mHandler;
+
+    /**
+     * Binder to receive calls from system server.
+     */
+    private final ITranslationService mInterface = new ITranslationService.Stub() {
+        @Override
+        public void onConnected() {
+            mHandler.sendMessage(obtainMessage(TranslationService::onConnected,
+                    TranslationService.this));
+        }
+
+        @Override
+        public void onDisconnected() {
+            mHandler.sendMessage(obtainMessage(TranslationService::onDisconnected,
+                    TranslationService.this));
+        }
+
+        @Override
+        public void onCreateTranslationSession(TranslationSpec sourceSpec, TranslationSpec destSpec,
+                int sessionId, IResultReceiver receiver) throws RemoteException {
+            mHandler.sendMessage(obtainMessage(TranslationService::handleOnCreateTranslationSession,
+                    TranslationService.this, sourceSpec, destSpec, sessionId, receiver));
+        }
+    };
+
+    /**
+     * Interface definition for a callback to be invoked when the translation is compleled.
+     */
+    public interface OnTranslationResultCallback {
+        /**
+         * Notifies the Android System that a translation request
+         * {@link TranslationService#onTranslationRequest(TranslationRequest, int,
+         * CancellationSignal, OnTranslationResultCallback)} was successfully fulfilled by the
+         * service.
+         *
+         * <p>This method should always be called, even if the service cannot fulfill the request
+         * (in which case it should be called with a TranslationResponse with
+         * {@link android.view.translation.TranslationResponse#TRANSLATION_STATUS_UNKNOWN_ERROR},
+         * or {@link android.view.translation.TranslationResponse
+         * #TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE}).
+         *
+         * @param response translation response for the provided request infos.
+         *
+         * @throws IllegalStateException if this method was already called.
+         */
+        void onTranslationSuccess(@NonNull TranslationResponse response);
+
+        /**
+         * TODO: implement javadoc
+         */
+        void onError();
+    }
+
+    /**
+     * Binder that receives calls from the app.
+     */
+    private final ITranslationDirectManager mClientInterface =
+            new ITranslationDirectManager.Stub() {
+                // TODO: Implement cancellation signal
+                @NonNull
+                private final CancellationSignal mCancellationSignal = new CancellationSignal();
+
+                @Override
+                public void onTranslationRequest(TranslationRequest request, int sessionId,
+                        ITranslationCallback callback, IResultReceiver receiver)
+                        throws RemoteException {
+                    // TODO(b/176464808): Currently, the API is used for both sync and async case.
+                    // It may work now, but maybe two methods is more cleaner. To think how to
+                    // define the APIs for these two cases.
+                    final ITranslationCallback cb = callback != null
+                            ? callback
+                            : new ITranslationCallback.Stub() {
+                                @Override
+                                public void onTranslationComplete(
+                                        TranslationResponse translationResponse)
+                                        throws RemoteException {
+                                    receiver.send(0,
+                                            SyncResultReceiver.bundleFor(translationResponse));
+                                }
+
+                                @Override
+                                public void onError() throws RemoteException {
+                                    //TODO: implement default error callback
+                                }
+                            };
+                    // TODO(b/176464808): make it a private member of client
+                    final OnTranslationResultCallback translationResultCallback =
+                            new OnTranslationResultCallbackWrapper(cb);
+                    mHandler.sendMessage(obtainMessage(TranslationService::onTranslationRequest,
+                            TranslationService.this, request, sessionId, mCancellationSignal,
+                            translationResultCallback));
+                }
+
+                @Override
+                public void onFinishTranslationSession(int sessionId) throws RemoteException {
+                    mHandler.sendMessage(obtainMessage(
+                            TranslationService::onFinishTranslationSession,
+                            TranslationService.this, sessionId));
+                }
+            };
+
+    @CallSuper
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        mHandler = new Handler(Looper.getMainLooper(), null, true);
+        BaseBundle.setShouldDefuse(true);
+    }
+
+    @Override
+    @Nullable
+    public final IBinder onBind(@NonNull Intent intent) {
+        if (SERVICE_INTERFACE.equals(intent.getAction())) {
+            return mInterface.asBinder();
+        }
+        Log.w(TAG, "Tried to bind to wrong intent (should be " + SERVICE_INTERFACE + ": " + intent);
+        return null;
+    }
+
+    /**
+     * Called when the Android system connects to service.
+     *
+     * <p>You should generally do initialization here rather than in {@link #onCreate}.
+     */
+    public void onConnected() {
+    }
+
+    /**
+     * Called when the Android system disconnects from the service.
+     *
+     * <p> At this point this service may no longer be an active {@link TranslationService}.
+     * It should not make calls on {@link TranslationManager} that requires the caller to be
+     * the current service.
+     */
+    public void onDisconnected() {
+    }
+
+    /**
+     * TODO: fill in javadoc.
+     *
+     * @param sourceSpec
+     * @param destSpec
+     * @param sessionId
+     */
+    // TODO(b/176464808): the session id won't be unique cross client/server process. Need to find
+    // solution to make it's safe.
+    public abstract void onCreateTranslationSession(@NonNull TranslationSpec sourceSpec,
+            @NonNull TranslationSpec destSpec, int sessionId);
+
+    /**
+     * TODO: fill in javadoc.
+     *
+     * @param sessionId
+     */
+    public abstract void onFinishTranslationSession(int sessionId);
+
+    /**
+     * TODO: fill in javadoc.
+     *
+     * @param request
+     * @param sessionId
+     * @param callback
+     * @param cancellationSignal
+     */
+    public abstract void onTranslationRequest(@NonNull TranslationRequest request, int sessionId,
+            @NonNull CancellationSignal cancellationSignal,
+            @NonNull OnTranslationResultCallback callback);
+
+    // TODO(b/176464808): Need to handle client dying case
+
+    // TODO(b/176464808): Need to handle the failure case. e.g. if the specs does not support
+
+    private void handleOnCreateTranslationSession(@NonNull TranslationSpec sourceSpec,
+            @NonNull TranslationSpec destSpec, int sessionId, IResultReceiver resultReceiver) {
+        try {
+            final Bundle extras = new Bundle();
+            extras.putBinder(EXTRA_SERVICE_BINDER, mClientInterface.asBinder());
+            extras.putInt(EXTRA_SESSION_ID, sessionId);
+            resultReceiver.send(0, extras);
+        } catch (RemoteException e) {
+            Log.w(TAG, "RemoteException sending client interface: " + e);
+        }
+        onCreateTranslationSession(sourceSpec, destSpec, sessionId);
+    }
+}
diff --git a/core/java/android/service/translation/TranslationServiceInfo.java b/core/java/android/service/translation/TranslationServiceInfo.java
new file mode 100644
index 0000000..18cc29d
--- /dev/null
+++ b/core/java/android/service/translation/TranslationServiceInfo.java
@@ -0,0 +1,173 @@
+/*
+ * 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.service.translation;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.AppGlobals;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ServiceInfo;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.os.RemoteException;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * {@link ServiceInfo} and meta-data about an {@link TranslationService}.
+ *
+ * @hide
+ */
+public final class TranslationServiceInfo {
+
+    private static final String TAG = "TranslationServiceInfo";
+    private static final String XML_TAG_SERVICE = "translation-service";
+
+    @NonNull
+    private final ServiceInfo mServiceInfo;
+
+    @Nullable
+    private final String mSettingsActivity;
+
+    private static ServiceInfo getServiceInfoOrThrow(ComponentName comp, boolean isTemp,
+            @UserIdInt int userId) throws PackageManager.NameNotFoundException {
+        int flags = PackageManager.GET_META_DATA;
+        if (!isTemp) {
+            flags |= PackageManager.MATCH_SYSTEM_ONLY;
+        }
+
+        ServiceInfo si = null;
+        try {
+            si = AppGlobals.getPackageManager().getServiceInfo(comp, flags, userId);
+        } catch (RemoteException e) {
+        }
+        if (si == null) {
+            throw new NameNotFoundException("Could not get serviceInfo for "
+                    + (isTemp ? " (temp)" : "(default system)")
+                    + " " + comp.flattenToShortString());
+        }
+        return si;
+    }
+
+    @NonNull
+    public ServiceInfo getServiceInfo() {
+        return mServiceInfo;
+    }
+
+    @Nullable
+    public String getSettingsActivity() {
+        return mSettingsActivity;
+    }
+
+    public TranslationServiceInfo(@NonNull Context context, @NonNull ComponentName comp,
+            boolean isTemporaryService, @UserIdInt int userId)
+            throws PackageManager.NameNotFoundException {
+        this(context, getServiceInfoOrThrow(comp, isTemporaryService, userId));
+    }
+
+    private TranslationServiceInfo(@NonNull Context context, @NonNull ServiceInfo si) {
+        // Check for permission.
+        if (!Manifest.permission.BIND_TRANSLATION_SERVICE.equals(si.permission)) {
+            Slog.w(TAG, "TranslationServiceInfo from '" + si.packageName
+                    + "' does not require permission "
+                    + Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE);
+            throw new SecurityException("Service does not require permission "
+                    + Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE);
+        }
+
+        mServiceInfo = si;
+
+        // Get the metadata, if declared.
+        // TODO: Try to find more easier way to do this.
+        final XmlResourceParser parser = si.loadXmlMetaData(context.getPackageManager(),
+                TranslationService.SERVICE_META_DATA);
+        if (parser == null) {
+            mSettingsActivity = null;
+            return;
+        }
+
+        String settingsActivity = null;
+
+        try {
+            final Resources resources = context.getPackageManager().getResourcesForApplication(
+                    si.applicationInfo);
+
+            int type = 0;
+            while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) {
+                type = parser.next();
+            }
+
+            if (XML_TAG_SERVICE.equals(parser.getName())) {
+                final AttributeSet allAttributes = Xml.asAttributeSet(parser);
+                TypedArray afsAttributes = null;
+                try {
+                    afsAttributes = resources.obtainAttributes(allAttributes,
+                            com.android.internal.R.styleable.TranslationService);
+                    settingsActivity = afsAttributes.getString(
+                            R.styleable.ContentCaptureService_settingsActivity);
+                } finally {
+                    if (afsAttributes != null) {
+                        afsAttributes.recycle();
+                    }
+                }
+            } else {
+                Log.e(TAG, "Meta-data does not start with translation-service tag");
+            }
+        } catch (PackageManager.NameNotFoundException | IOException | XmlPullParserException e) {
+            Log.e(TAG, "Error parsing auto fill service meta-data", e);
+        }
+
+        mSettingsActivity = settingsActivity;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder();
+        builder.append(getClass().getSimpleName());
+        builder.append("[").append(mServiceInfo);
+        builder.append(", settings:").append(mSettingsActivity);
+        return builder.toString();
+    }
+
+    /**
+     * Dumps the service information.
+     */
+    public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
+        pw.print(prefix);
+        pw.print("Component: ");
+        pw.println(getServiceInfo().getComponentName());
+        pw.print(prefix);
+        pw.print("Settings: ");
+        pw.println(mSettingsActivity);
+    }
+}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 0f53215..e8584da 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8821,6 +8821,7 @@
                 structure.setAutofillValue(getAutofillValue());
             }
             structure.setImportantForAutofill(getImportantForAutofill());
+            structure.setOnReceiveContentMimeTypes(getOnReceiveContentMimeTypes());
         }
 
         int ignoredParentLeft = 0;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index d863ea5..0097b2e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -3150,6 +3150,8 @@
 
         mImeFocusController.onTraversal(hasWindowFocus, mWindowAttributes);
 
+        final boolean wasReportNextDraw = mReportNextDraw;
+
         // Remember if we must report the next draw.
         if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
             reportNextDraw();
@@ -3177,12 +3179,25 @@
             if (isViewVisible) {
                 // Try again
                 scheduleTraversals();
-            } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
-                for (int i = 0; i < mPendingTransitions.size(); ++i) {
-                    mPendingTransitions.get(i).endChangingAnimations();
+            } else {
+                if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
+                    for (int i = 0; i < mPendingTransitions.size(); ++i) {
+                        mPendingTransitions.get(i).endChangingAnimations();
+                    }
+                    mPendingTransitions.clear();
                 }
-                mPendingTransitions.clear();
+
+                // We may never draw since it's not visible. Report back that we're finished
+                // drawing.
+                if (!wasReportNextDraw && mReportNextDraw) {
+                    mReportNextDraw = false;
+                    pendingDrawFinished();
+                }
             }
+
+            // We were unable to draw this traversal. Unset this flag since we'll block without
+            // ever being able to draw again
+            mNextDrawUseBlastSync = false;
         }
 
         if (mAttachInfo.mContentCaptureEvents != null) {
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index 29ce231..f5aa97a 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -372,6 +372,14 @@
     public void setImportantForAutofill(@AutofillImportance int mode) {}
 
     /**
+     * Sets the MIME types accepted by this view. See {@link View#getOnReceiveContentMimeTypes()}.
+     *
+     * <p>Should only be set when the node is used for Autofill or Content Capture purposes - it
+     * will be ignored when used for Assist.
+     */
+    public void setOnReceiveContentMimeTypes(@Nullable String[] mimeTypes) {}
+
+    /**
      * Sets the {@link android.text.InputType} bits of this node.
      *
      * @param inputType inputType bits as defined by {@link android.text.InputType}.
diff --git a/core/java/android/view/contentcapture/ViewNode.java b/core/java/android/view/contentcapture/ViewNode.java
index e731d4b..4e9c229 100644
--- a/core/java/android/view/contentcapture/ViewNode.java
+++ b/core/java/android/view/contentcapture/ViewNode.java
@@ -81,6 +81,7 @@
     private static final long FLAGS_HAS_AUTOFILL_HINTS = 1L << 33;
     private static final long FLAGS_HAS_AUTOFILL_OPTIONS = 1L << 34;
     private static final long FLAGS_HAS_HINT_ID_ENTRY = 1L << 35;
+    private static final long FLAGS_HAS_MIME_TYPES = 1L << 36;
 
     /** Flags used to optimize what's written to the parcel */
     private long mFlags;
@@ -113,6 +114,7 @@
     private String[] mAutofillHints;
     private AutofillValue mAutofillValue;
     private CharSequence[] mAutofillOptions;
+    private String[] mOnReceiveContentMimeTypes;
 
     /** @hide */
     public ViewNode() {
@@ -169,6 +171,9 @@
         if ((nodeFlags & FLAGS_HAS_LOCALE_LIST) != 0) {
             mLocaleList = parcel.readParcelable(null);
         }
+        if ((nodeFlags & FLAGS_HAS_MIME_TYPES) != 0) {
+            mOnReceiveContentMimeTypes = parcel.readStringArray();
+        }
         if ((nodeFlags & FLAGS_HAS_INPUT_TYPE) != 0) {
             mInputType = parcel.readInt();
         }
@@ -463,6 +468,12 @@
         return mAutofillOptions;
     }
 
+    @Override
+    @Nullable
+    public String[] getOnReceiveContentMimeTypes() {
+        return mOnReceiveContentMimeTypes;
+    }
+
     @Nullable
     @Override
     public LocaleList getLocaleList() {
@@ -508,6 +519,9 @@
         if (mLocaleList != null) {
             nodeFlags |= FLAGS_HAS_LOCALE_LIST;
         }
+        if (mOnReceiveContentMimeTypes != null) {
+            nodeFlags |= FLAGS_HAS_MIME_TYPES;
+        }
         if (mInputType != 0) {
             nodeFlags |= FLAGS_HAS_INPUT_TYPE;
         }
@@ -584,6 +598,9 @@
         if ((nodeFlags & FLAGS_HAS_LOCALE_LIST) != 0) {
             parcel.writeParcelable(mLocaleList, 0);
         }
+        if ((nodeFlags & FLAGS_HAS_MIME_TYPES) != 0) {
+            parcel.writeStringArray(mOnReceiveContentMimeTypes);
+        }
         if ((nodeFlags & FLAGS_HAS_INPUT_TYPE) != 0) {
             parcel.writeInt(mInputType);
         }
@@ -912,6 +929,11 @@
         }
 
         @Override
+        public void setOnReceiveContentMimeTypes(@Nullable String[] mimeTypes) {
+            mNode.mOnReceiveContentMimeTypes = mimeTypes;
+        }
+
+        @Override
         public void setAutofillHints(String[] hints) {
             mNode.mAutofillHints = hints;
         }
diff --git a/core/java/android/view/translation/ITranslationDirectManager.aidl b/core/java/android/view/translation/ITranslationDirectManager.aidl
new file mode 100644
index 0000000..358f99a
--- /dev/null
+++ b/core/java/android/view/translation/ITranslationDirectManager.aidl
@@ -0,0 +1,33 @@
+/*
+ * 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.service.translation.TranslationRequest;
+import android.service.translation.ITranslationCallback;
+import com.android.internal.os.IResultReceiver;
+
+/**
+  * Interface between an app (TranslationManager / Translator) and the remote TranslationService
+  * providing the TranslationService implementation.
+  *
+  * @hide
+  */
+oneway interface ITranslationDirectManager {
+    void onTranslationRequest(in TranslationRequest request, int sessionId,
+         in ITranslationCallback callback, in IResultReceiver receiver);
+    void onFinishTranslationSession(int sessionId);
+}
diff --git a/core/java/android/view/translation/ITranslationManager.aidl b/core/java/android/view/translation/ITranslationManager.aidl
new file mode 100644
index 0000000..73addf4
--- /dev/null
+++ b/core/java/android/view/translation/ITranslationManager.aidl
@@ -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 android.view.translation;
+
+import android.service.translation.TranslationRequest;
+import android.view.translation.TranslationSpec;
+import com.android.internal.os.IResultReceiver;
+
+/**
+ * Mediator between apps being translated and translation service implementation.
+ *
+ * {@hide}
+ */
+oneway interface ITranslationManager {
+    void getSupportedLocales(in IResultReceiver receiver, int userId);
+    void onSessionCreated(in TranslationSpec sourceSpec, in TranslationSpec destSpec,
+         int sessionId, in IResultReceiver receiver, int userId);
+}
diff --git a/core/java/android/view/translation/OWNERS b/core/java/android/view/translation/OWNERS
new file mode 100644
index 0000000..a1e663a
--- /dev/null
+++ b/core/java/android/view/translation/OWNERS
@@ -0,0 +1,8 @@
+# Bug component: 994311
+
+adamhe@google.com
+augale@google.com
+joannechung@google.com
+lpeter@google.com
+svetoslavganov@google.com
+tymtsai@google.com
diff --git a/core/java/android/view/translation/TranslationData.aidl b/core/java/android/view/translation/TranslationData.aidl
new file mode 100644
index 0000000..40f21a6
--- /dev/null
+++ b/core/java/android/view/translation/TranslationData.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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;
+
+parcelable TranslationData;
diff --git a/core/java/android/view/translation/TranslationManager.java b/core/java/android/view/translation/TranslationManager.java
new file mode 100644
index 0000000..6554e1a
--- /dev/null
+++ b/core/java/android/view/translation/TranslationManager.java
@@ -0,0 +1,201 @@
+/*
+ * 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.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
+import android.annotation.SystemService;
+import android.annotation.WorkerThread;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.service.translation.TranslationService;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.Pair;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.SyncResultReceiver;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * The {@link TranslationManager} class provides ways for apps to integrate and use the
+ * translation framework.
+ *
+ * <p>The TranslationManager manages {@link Translator}s and help bridge client calls to
+ * the server {@link android.service.translation.TranslationService} </p>
+ */
+@SystemService(Context.TRANSLATION_MANAGER_SERVICE)
+@RequiresFeature(PackageManager.FEATURE_TRANSLATION)
+public final class TranslationManager {
+
+    private static final String TAG = "TranslationManager";
+
+    /**
+     * Timeout for calls to system_server.
+     */
+    static final int SYNC_CALLS_TIMEOUT_MS = 5000;
+    /**
+     * The result code from result receiver success.
+     * @hide
+     */
+    public static final int STATUS_SYNC_CALL_SUCCESS = 1;
+    /**
+     * The result code from result receiver fail.
+     * @hide
+     */
+    public static final int STATUS_SYNC_CALL_FAIL = 2;
+
+    private static final Random ID_GENERATOR = new Random();
+    private final Object mLock = new Object();
+
+    @NonNull
+    private final Context mContext;
+
+    private final ITranslationManager mService;
+
+    @Nullable
+    @GuardedBy("mLock")
+    private ITranslationDirectManager mDirectServiceBinder;
+
+    @NonNull
+    @GuardedBy("mLock")
+    private final SparseArray<Translator> mTranslators = new SparseArray<>();
+
+    @NonNull
+    @GuardedBy("mLock")
+    private final ArrayMap<Pair<TranslationSpec, TranslationSpec>, Integer> mTranslatorIds =
+            new ArrayMap<>();
+
+    @NonNull
+    private final Handler mHandler;
+
+    private static final AtomicInteger sAvailableRequestId = new AtomicInteger(1);
+
+    /**
+     * @hide
+     */
+    public TranslationManager(@NonNull Context context, ITranslationManager service) {
+        mContext = Objects.requireNonNull(context, "context cannot be null");
+        mService = service;
+
+        mHandler = Handler.createAsync(Looper.getMainLooper());
+    }
+
+    /**
+     * Create a Translator for translation.
+     *
+     * <p><strong>NOTE: </strong>Call on a worker thread.
+     *
+     * @param sourceSpec {@link TranslationSpec} for the data to be translated.
+     * @param destSpec {@link TranslationSpec} for the translated data.
+     * @return a {@link Translator} to be used for calling translation APIs.
+     */
+    @Nullable
+    @WorkerThread
+    public Translator createTranslator(@NonNull TranslationSpec sourceSpec,
+            @NonNull TranslationSpec destSpec) {
+        Objects.requireNonNull(sourceSpec, "sourceSpec cannot be null");
+        Objects.requireNonNull(sourceSpec, "destSpec cannot be null");
+
+        synchronized (mLock) {
+            // TODO(b/176464808): Disallow multiple Translator now, it will throw
+            //  IllegalStateException. Need to discuss if we can allow multiple Translators.
+            final Pair<TranslationSpec, TranslationSpec> specs = new Pair<>(sourceSpec, destSpec);
+            if (mTranslatorIds.containsKey(specs)) {
+                return mTranslators.get(mTranslatorIds.get(specs));
+            }
+
+            int translatorId;
+            do {
+                translatorId = Math.abs(ID_GENERATOR.nextInt());
+            } while (translatorId == 0 || mTranslators.indexOfKey(translatorId) >= 0);
+
+            final Translator newTranslator = new Translator(mContext, sourceSpec, destSpec,
+                    translatorId, this, mHandler, mService);
+            // Start the Translator session and wait for the result
+            newTranslator.start();
+            try {
+                if (!newTranslator.isSessionCreated()) {
+                    return null;
+                }
+                mTranslators.put(translatorId, newTranslator);
+                mTranslatorIds.put(specs, translatorId);
+                return newTranslator;
+            } catch (Translator.ServiceBinderReceiver.TimeoutException e) {
+                // TODO(b/176464808): maybe make SyncResultReceiver.TimeoutException constructor
+                //  public and use it.
+                Log.e(TAG, "Timed out getting create session: " + e);
+                return null;
+            }
+        }
+    }
+
+    /**
+     * Returns a list of locales supported by the {@link TranslationService}.
+     *
+     * <p><strong>NOTE: </strong>Call on a worker thread.
+     *
+     * TODO: Change to correct language/locale format
+     */
+    @NonNull
+    @WorkerThread
+    public List<String> getSupportedLocales() {
+        try {
+            // TODO: implement it
+            final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
+            mService.getSupportedLocales(receiver, mContext.getUserId());
+            int resutCode = receiver.getIntResult();
+            if (resutCode != STATUS_SYNC_CALL_SUCCESS) {
+                return Collections.emptyList();
+            }
+            return receiver.getParcelableResult();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (SyncResultReceiver.TimeoutException e) {
+            Log.e(TAG, "Timed out getting supported locales: " + e);
+            return Collections.emptyList();
+        }
+    }
+
+    void removeTranslator(int id) {
+        synchronized (mLock) {
+            mTranslators.remove(id);
+            for (int i = 0; i < mTranslatorIds.size(); i++) {
+                if (mTranslatorIds.valueAt(i) == id) {
+                    mTranslatorIds.removeAt(i);
+                    break;
+                }
+            }
+        }
+    }
+
+    AtomicInteger getAvailableRequestId() {
+        synchronized (mLock) {
+            return sAvailableRequestId;
+        }
+    }
+}
diff --git a/core/java/android/view/translation/TranslationRequest.aidl b/core/java/android/view/translation/TranslationRequest.aidl
new file mode 100644
index 0000000..c34bf30
--- /dev/null
+++ b/core/java/android/view/translation/TranslationRequest.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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;
+
+parcelable TranslationRequest;
diff --git a/core/java/android/view/translation/TranslationRequest.java b/core/java/android/view/translation/TranslationRequest.java
new file mode 100644
index 0000000..a5e3f75
--- /dev/null
+++ b/core/java/android/view/translation/TranslationRequest.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.view.translation;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcelable;
+import android.view.autofill.AutofillId;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * Wrapper class for data to be translated by {@link android.service.translation.TranslationService}
+ */
+@DataClass(genToString = true, genBuilder = true)
+public final class TranslationRequest implements Parcelable {
+
+    @Nullable
+    private final AutofillId mAutofillId;
+
+    @Nullable
+    private final CharSequence mTranslationText;
+
+    public TranslationRequest(@Nullable CharSequence text) {
+        mAutofillId = null;
+        mTranslationText = text;
+    }
+
+    private static CharSequence defaultTranslationText() {
+        return null;
+    }
+
+    private static AutofillId defaultAutofillId() {
+        return null;
+    }
+
+
+
+    // Code below generated by codegen v1.0.22.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/translation/TranslationRequest.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 */ TranslationRequest(
+            @Nullable AutofillId autofillId,
+            @Nullable CharSequence translationText) {
+        this.mAutofillId = autofillId;
+        this.mTranslationText = translationText;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public @Nullable AutofillId getAutofillId() {
+        return mAutofillId;
+    }
+
+    @DataClass.Generated.Member
+    public @Nullable CharSequence getTranslationText() {
+        return mTranslationText;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "TranslationRequest { " +
+                "autofillId = " + mAutofillId + ", " +
+                "translationText = " + mTranslationText +
+        " }";
+    }
+
+    @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 (mAutofillId != null) flg |= 0x1;
+        if (mTranslationText != null) flg |= 0x2;
+        dest.writeByte(flg);
+        if (mAutofillId != null) dest.writeTypedObject(mAutofillId, flags);
+        if (mTranslationText != null) dest.writeCharSequence(mTranslationText);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ TranslationRequest(@NonNull android.os.Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        byte flg = in.readByte();
+        AutofillId autofillId = (flg & 0x1) == 0 ? null : (AutofillId) in.readTypedObject(AutofillId.CREATOR);
+        CharSequence translationText = (flg & 0x2) == 0 ? null : (CharSequence) in.readCharSequence();
+
+        this.mAutofillId = autofillId;
+        this.mTranslationText = translationText;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<TranslationRequest> CREATOR
+            = new Parcelable.Creator<TranslationRequest>() {
+        @Override
+        public TranslationRequest[] newArray(int size) {
+            return new TranslationRequest[size];
+        }
+
+        @Override
+        public TranslationRequest createFromParcel(@NonNull android.os.Parcel in) {
+            return new TranslationRequest(in);
+        }
+    };
+
+    /**
+     * A builder for {@link TranslationRequest}
+     */
+    @SuppressWarnings("WeakerAccess")
+    @DataClass.Generated.Member
+    public static final class Builder {
+
+        private @Nullable AutofillId mAutofillId;
+        private @Nullable CharSequence mTranslationText;
+
+        private long mBuilderFieldsSet = 0L;
+
+        public Builder() {
+        }
+
+        @DataClass.Generated.Member
+        public @NonNull Builder setAutofillId(@NonNull AutofillId value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x1;
+            mAutofillId = value;
+            return this;
+        }
+
+        @DataClass.Generated.Member
+        public @NonNull Builder setTranslationText(@NonNull CharSequence value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x2;
+            mTranslationText = value;
+            return this;
+        }
+
+        /** Builds the instance. This builder should not be touched after calling this! */
+        public @NonNull TranslationRequest build() {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x4; // Mark builder used
+
+            if ((mBuilderFieldsSet & 0x1) == 0) {
+                mAutofillId = defaultAutofillId();
+            }
+            if ((mBuilderFieldsSet & 0x2) == 0) {
+                mTranslationText = defaultTranslationText();
+            }
+            TranslationRequest o = new TranslationRequest(
+                    mAutofillId,
+                    mTranslationText);
+            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 = 1610060189421L,
+            codegenVersion = "1.0.22",
+            sourceFile = "frameworks/base/core/java/android/view/translation/TranslationRequest.java",
+            inputSignatures = "private final @android.annotation.Nullable android.view.autofill.AutofillId mAutofillId\nprivate final @android.annotation.Nullable java.lang.CharSequence mTranslationText\nprivate static  java.lang.CharSequence defaultTranslationText()\nprivate static  android.view.autofill.AutofillId defaultAutofillId()\nclass TranslationRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genBuilder=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/view/translation/TranslationResponse.aidl b/core/java/android/view/translation/TranslationResponse.aidl
new file mode 100644
index 0000000..e5350bb
--- /dev/null
+++ b/core/java/android/view/translation/TranslationResponse.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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;
+
+parcelable TranslationResponse;
diff --git a/core/java/android/view/translation/TranslationResponse.java b/core/java/android/view/translation/TranslationResponse.java
new file mode 100644
index 0000000..d29063f
--- /dev/null
+++ b/core/java/android/view/translation/TranslationResponse.java
@@ -0,0 +1,311 @@
+/*
+ * 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.os.Parcel;
+import android.os.Parcelable;
+import android.service.translation.TranslationService;
+
+import com.android.internal.util.DataClass;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Response from the {@link TranslationService}, which contains the translated result.
+ */
+@DataClass(genBuilder = true, genToString = true, genHiddenConstDefs = true)
+public final class TranslationResponse implements Parcelable {
+
+    /**
+     * The {@link TranslationService} was successful in translating.
+     */
+    public static final int TRANSLATION_STATUS_SUCCESS = 0;
+    /**
+     * The {@link TranslationService} returned unknown translation result.
+     */
+    public static final int TRANSLATION_STATUS_UNKNOWN_ERROR = 1;
+    /**
+     * The language of the request is not available to be translated.
+     */
+    public static final int TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE = 2;
+
+    /**
+     * The translation result status code.
+     */
+    private final @TranslationStatus int mTranslationStatus;
+    /**
+     * The translation results. If there is no translation result, set it with an empty list.
+     */
+    @NonNull
+    private List<TranslationRequest> mTranslations = new ArrayList();
+
+
+
+
+    // Code below generated by codegen v1.0.22.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/translation/TranslationResponse.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /** @hide */
+    @IntDef(prefix = "TRANSLATION_STATUS_", value = {
+        TRANSLATION_STATUS_SUCCESS,
+        TRANSLATION_STATUS_UNKNOWN_ERROR,
+        TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @DataClass.Generated.Member
+    public @interface TranslationStatus {}
+
+    /** @hide */
+    @DataClass.Generated.Member
+    public static String translationStatusToString(@TranslationStatus int value) {
+        switch (value) {
+            case TRANSLATION_STATUS_SUCCESS:
+                    return "TRANSLATION_STATUS_SUCCESS";
+            case TRANSLATION_STATUS_UNKNOWN_ERROR:
+                    return "TRANSLATION_STATUS_UNKNOWN_ERROR";
+            case TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE:
+                    return "TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE";
+            default: return Integer.toHexString(value);
+        }
+    }
+
+    @DataClass.Generated.Member
+    /* package-private */ TranslationResponse(
+            @TranslationStatus int translationStatus,
+            @NonNull List<TranslationRequest> translations) {
+        this.mTranslationStatus = translationStatus;
+
+        if (!(mTranslationStatus == TRANSLATION_STATUS_SUCCESS)
+                && !(mTranslationStatus == TRANSLATION_STATUS_UNKNOWN_ERROR)
+                && !(mTranslationStatus == TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE)) {
+            throw new java.lang.IllegalArgumentException(
+                    "translationStatus was " + mTranslationStatus + " but must be one of: "
+                            + "TRANSLATION_STATUS_SUCCESS(" + TRANSLATION_STATUS_SUCCESS + "), "
+                            + "TRANSLATION_STATUS_UNKNOWN_ERROR(" + TRANSLATION_STATUS_UNKNOWN_ERROR + "), "
+                            + "TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE(" + TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE + ")");
+        }
+
+        this.mTranslations = translations;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mTranslations);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    /**
+     * The translation result status code.
+     */
+    @DataClass.Generated.Member
+    public @TranslationStatus int getTranslationStatus() {
+        return mTranslationStatus;
+    }
+
+    /**
+     * The translation results. If there is no translation result, set it with an empty list.
+     */
+    @DataClass.Generated.Member
+    public @NonNull List<TranslationRequest> getTranslations() {
+        return mTranslations;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "TranslationResponse { " +
+                "translationStatus = " + translationStatusToString(mTranslationStatus) + ", " +
+                "translations = " + mTranslations +
+        " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeInt(mTranslationStatus);
+        dest.writeParcelableList(mTranslations, flags);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ TranslationResponse(@NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        int translationStatus = in.readInt();
+        List<TranslationRequest> translations = new ArrayList<>();
+        in.readParcelableList(translations, TranslationRequest.class.getClassLoader());
+
+        this.mTranslationStatus = translationStatus;
+
+        if (!(mTranslationStatus == TRANSLATION_STATUS_SUCCESS)
+                && !(mTranslationStatus == TRANSLATION_STATUS_UNKNOWN_ERROR)
+                && !(mTranslationStatus == TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE)) {
+            throw new java.lang.IllegalArgumentException(
+                    "translationStatus was " + mTranslationStatus + " but must be one of: "
+                            + "TRANSLATION_STATUS_SUCCESS(" + TRANSLATION_STATUS_SUCCESS + "), "
+                            + "TRANSLATION_STATUS_UNKNOWN_ERROR(" + TRANSLATION_STATUS_UNKNOWN_ERROR + "), "
+                            + "TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE(" + TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE + ")");
+        }
+
+        this.mTranslations = translations;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mTranslations);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<TranslationResponse> CREATOR
+            = new Parcelable.Creator<TranslationResponse>() {
+        @Override
+        public TranslationResponse[] newArray(int size) {
+            return new TranslationResponse[size];
+        }
+
+        @Override
+        public TranslationResponse createFromParcel(@NonNull Parcel in) {
+            return new TranslationResponse(in);
+        }
+    };
+
+    /**
+     * A builder for {@link TranslationResponse}
+     */
+    @SuppressWarnings("WeakerAccess")
+    @DataClass.Generated.Member
+    public static final class Builder {
+
+        private @TranslationStatus int mTranslationStatus;
+        private @NonNull List<TranslationRequest> mTranslations;
+
+        private long mBuilderFieldsSet = 0L;
+
+        /**
+         * Creates a new Builder.
+         *
+         * @param translationStatus
+         *   The translation result status code.
+         */
+        public Builder(
+                @TranslationStatus int translationStatus) {
+            mTranslationStatus = translationStatus;
+
+            if (!(mTranslationStatus == TRANSLATION_STATUS_SUCCESS)
+                    && !(mTranslationStatus == TRANSLATION_STATUS_UNKNOWN_ERROR)
+                    && !(mTranslationStatus == TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE)) {
+                throw new java.lang.IllegalArgumentException(
+                        "translationStatus was " + mTranslationStatus + " but must be one of: "
+                                + "TRANSLATION_STATUS_SUCCESS(" + TRANSLATION_STATUS_SUCCESS + "), "
+                                + "TRANSLATION_STATUS_UNKNOWN_ERROR(" + TRANSLATION_STATUS_UNKNOWN_ERROR + "), "
+                                + "TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE(" + TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE + ")");
+            }
+
+        }
+
+        /**
+         * The translation result status code.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setTranslationStatus(@TranslationStatus int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x1;
+            mTranslationStatus = value;
+            return this;
+        }
+
+        /**
+         * The translation results. If there is no translation result, set it with an empty list.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setTranslations(@NonNull List<TranslationRequest> value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x2;
+            mTranslations = value;
+            return this;
+        }
+
+        /** @see #setTranslations */
+        @DataClass.Generated.Member
+        public @NonNull Builder addTranslations(@NonNull TranslationRequest value) {
+            // You can refine this method's name by providing item's singular name, e.g.:
+            // @DataClass.PluralOf("item")) mItems = ...
+
+            if (mTranslations == null) setTranslations(new ArrayList<>());
+            mTranslations.add(value);
+            return this;
+        }
+
+        /** Builds the instance. This builder should not be touched after calling this! */
+        public @NonNull TranslationResponse build() {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x4; // Mark builder used
+
+            if ((mBuilderFieldsSet & 0x2) == 0) {
+                mTranslations = new ArrayList();
+            }
+            TranslationResponse o = new TranslationResponse(
+                    mTranslationStatus,
+                    mTranslations);
+            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 = 1609973911361L,
+            codegenVersion = "1.0.22",
+            sourceFile = "frameworks/base/core/java/android/view/translation/TranslationResponse.java",
+            inputSignatures = "public static final  int TRANSLATION_STATUS_SUCCESS\npublic static final  int TRANSLATION_STATUS_UNKNOWN_ERROR\npublic static final  int TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE\nprivate final @android.view.translation.TranslationResponse.TranslationStatus int mTranslationStatus\nprivate @android.annotation.NonNull java.util.List<android.view.translation.TranslationRequest> mTranslations\nclass TranslationResponse extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genToString=true, genHiddenConstDefs=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/view/translation/TranslationSpec.aidl b/core/java/android/view/translation/TranslationSpec.aidl
new file mode 100644
index 0000000..875d798
--- /dev/null
+++ b/core/java/android/view/translation/TranslationSpec.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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;
+
+parcelable TranslationSpec;
diff --git a/core/java/android/view/translation/TranslationSpec.java b/core/java/android/view/translation/TranslationSpec.java
new file mode 100644
index 0000000..ab1bc47
--- /dev/null
+++ b/core/java/android/view/translation/TranslationSpec.java
@@ -0,0 +1,189 @@
+/*
+ * 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.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * Specs and additional info for the translation data.
+ *
+ * <p>This spec help specify information such as the language/locale for the translation, as well
+ * as the data format for the translation (text, audio, etc.)</p>
+ */
+@DataClass(genEqualsHashCode = true, genHiddenConstDefs = true)
+public final class TranslationSpec implements Parcelable {
+
+    /** Data format for translation is text. */
+    public static final int DATA_FORMAT_TEXT = 1;
+
+    /** @hide */
+    @android.annotation.IntDef(prefix = "DATA_FORMAT_", value = {
+            DATA_FORMAT_TEXT
+    })
+    @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
+    @DataClass.Generated.Member
+    public @interface DataFormat {}
+
+    /**
+     * String representation of language codes e.g. "en", "es", etc.
+     */
+    private final @NonNull String mLanguage;
+
+    private final @DataFormat int mDataFormat;
+
+
+
+    // Code below generated by codegen v1.0.22.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/translation/TranslationSpec.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /**
+     * Creates a new TranslationSpec.
+     *
+     * @param language
+     *   String representation of language codes e.g. "en", "es", etc.
+     */
+    @DataClass.Generated.Member
+    public TranslationSpec(
+            @NonNull String language,
+            @DataFormat int dataFormat) {
+        this.mLanguage = language;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mLanguage);
+        this.mDataFormat = dataFormat;
+        com.android.internal.util.AnnotationValidations.validate(
+                DataFormat.class, null, mDataFormat);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    /**
+     * String representation of language codes e.g. "en", "es", etc.
+     */
+    @DataClass.Generated.Member
+    public @NonNull String getLanguage() {
+        return mLanguage;
+    }
+
+    @DataClass.Generated.Member
+    public @DataFormat int getDataFormat() {
+        return mDataFormat;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public boolean equals(@android.annotation.Nullable Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(TranslationSpec other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        TranslationSpec that = (TranslationSpec) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && java.util.Objects.equals(mLanguage, that.mLanguage)
+                && mDataFormat == that.mDataFormat;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int hashCode() {
+        // You can override field hashCode logic by defining methods like:
+        // int fieldNameHashCode() { ... }
+
+        int _hash = 1;
+        _hash = 31 * _hash + java.util.Objects.hashCode(mLanguage);
+        _hash = 31 * _hash + mDataFormat;
+        return _hash;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeString(mLanguage);
+        dest.writeInt(mDataFormat);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ TranslationSpec(@NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        String language = in.readString();
+        int dataFormat = in.readInt();
+
+        this.mLanguage = language;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mLanguage);
+        this.mDataFormat = dataFormat;
+        com.android.internal.util.AnnotationValidations.validate(
+                DataFormat.class, null, mDataFormat);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<TranslationSpec> CREATOR
+            = new Parcelable.Creator<TranslationSpec>() {
+        @Override
+        public TranslationSpec[] newArray(int size) {
+            return new TranslationSpec[size];
+        }
+
+        @Override
+        public TranslationSpec createFromParcel(@NonNull Parcel in) {
+            return new TranslationSpec(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1609964630624L,
+            codegenVersion = "1.0.22",
+            sourceFile = "frameworks/base/core/java/android/view/translation/TranslationSpec.java",
+            inputSignatures = "public static final  int DATA_FORMAT_TEXT\nprivate final @android.annotation.NonNull java.lang.String mLanguage\nprivate final @android.view.translation.TranslationSpec.DataFormat int mDataFormat\nclass TranslationSpec extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genHiddenConstDefs=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/view/translation/Translator.java b/core/java/android/view/translation/Translator.java
new file mode 100644
index 0000000..675f32b
--- /dev/null
+++ b/core/java/android/view/translation/Translator.java
@@ -0,0 +1,298 @@
+/*
+ * 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 static android.view.translation.TranslationManager.STATUS_SYNC_CALL_FAIL;
+import static android.view.translation.TranslationManager.SYNC_CALLS_TIMEOUT_MS;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.WorkerThread;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.IResultReceiver;
+import com.android.internal.util.SyncResultReceiver;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Objects;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * The {@link Translator} for translation, defined by a source and a dest {@link TranslationSpec}.
+ */
+@SuppressLint("NotCloseable")
+public class Translator {
+
+    private static final String TAG = "Translator";
+
+    // TODO: make this configurable and cross the Translation component
+    private static boolean sDEBUG = false;
+
+    private final Object mLock = new Object();
+
+    private int mId;
+
+    @NonNull
+    private final Context mContext;
+
+    @NonNull
+    private final TranslationSpec mSourceSpec;
+
+    @NonNull
+    private final TranslationSpec mDestSpec;
+
+    @NonNull
+    private final TranslationManager mManager;
+
+    @NonNull
+    private final Handler mHandler;
+
+    /**
+     * Interface to the system_server binder object.
+     */
+    private ITranslationManager mSystemServerBinder;
+
+    /**
+     * Direct interface to the TranslationService binder object.
+     */
+    @Nullable
+    private ITranslationDirectManager mDirectServiceBinder;
+
+    @NonNull
+    private final ServiceBinderReceiver mServiceBinderReceiver;
+
+    @GuardedBy("mLock")
+    private boolean mDestroyed;
+
+    /**
+     * Name of the {@link IResultReceiver} extra used to pass the binder interface to Translator.
+     * @hide
+     */
+    public static final String EXTRA_SERVICE_BINDER = "binder";
+    /**
+     * Name of the extra used to pass the session id to Translator.
+     * @hide
+     */
+    public static final String EXTRA_SESSION_ID = "sessionId";
+
+    static class ServiceBinderReceiver extends IResultReceiver.Stub {
+        private final WeakReference<Translator> mTranslator;
+        private final CountDownLatch mLatch = new CountDownLatch(1);
+        private int mSessionId;
+
+        ServiceBinderReceiver(Translator translator) {
+            mTranslator = new WeakReference<>(translator);
+        }
+
+        int getSessionStateResult() throws TimeoutException {
+            try {
+                if (!mLatch.await(SYNC_CALLS_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+                    throw new TimeoutException(
+                            "Session not created in " + SYNC_CALLS_TIMEOUT_MS + "ms");
+                }
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                throw new TimeoutException("Session not created because interrupted");
+            }
+            return mSessionId;
+        }
+
+        @Override
+        public void send(int resultCode, Bundle resultData) {
+            if (resultCode == STATUS_SYNC_CALL_FAIL) {
+                mLatch.countDown();
+                return;
+            }
+            mSessionId = resultData.getInt(EXTRA_SESSION_ID);
+            final Translator translator = mTranslator.get();
+            if (translator == null) {
+                Log.w(TAG, "received result after session is finished");
+                return;
+            }
+            final IBinder binder;
+            if (resultData != null) {
+                binder = resultData.getBinder(EXTRA_SERVICE_BINDER);
+                if (binder == null) {
+                    Log.wtf(TAG, "No " + EXTRA_SERVICE_BINDER + " extra result");
+                    return;
+                }
+            } else {
+                binder = null;
+            }
+            translator.setServiceBinder(binder);
+            mLatch.countDown();
+        }
+
+        // TODO(b/176464808): maybe make SyncResultReceiver.TimeoutException constructor public
+        //  and use it.
+        static final class TimeoutException extends Exception {
+            private TimeoutException(String msg) {
+                super(msg);
+            }
+        }
+    }
+
+    /**
+     * Create the Translator.
+     *
+     * @hide
+     */
+    public Translator(@NonNull Context context,
+            @NonNull TranslationSpec sourceSpec,
+            @NonNull TranslationSpec destSpec, int sessionId,
+            @NonNull TranslationManager translationManager, @NonNull Handler handler,
+            @Nullable ITranslationManager systemServerBinder) {
+        mContext = context;
+        mSourceSpec = sourceSpec;
+        mDestSpec = destSpec;
+        mId = sessionId;
+        mManager = translationManager;
+        mHandler = handler;
+        mSystemServerBinder = systemServerBinder;
+        mServiceBinderReceiver = new ServiceBinderReceiver(this);
+    }
+
+    /**
+     * Starts this Translator session.
+     */
+    void start() {
+        try {
+            mSystemServerBinder.onSessionCreated(mSourceSpec, mDestSpec, mId,
+                    mServiceBinderReceiver, mContext.getUserId());
+        } catch (RemoteException e) {
+            Log.w(TAG, "RemoteException calling startSession(): " + e);
+        }
+    }
+
+    /**
+     * Wait this Translator session created.
+     *
+     * @return {@code true} if the session is created successfully.
+     */
+    boolean isSessionCreated() throws ServiceBinderReceiver.TimeoutException {
+        int receivedId = mServiceBinderReceiver.getSessionStateResult();
+        return receivedId > 0;
+    }
+
+    private int getNextRequestId() {
+        // Get from manager to keep the request id unique to different Translators
+        return mManager.getAvailableRequestId().getAndIncrement();
+    }
+
+    private void setServiceBinder(@Nullable IBinder binder) {
+        synchronized (mLock) {
+            if (mDirectServiceBinder != null) {
+                return;
+            }
+            if (binder != null) {
+                mDirectServiceBinder = ITranslationDirectManager.Stub.asInterface(binder);
+            }
+        }
+    }
+
+    /** @hide */
+    public int getTranslatorId() {
+        return mId;
+    }
+
+    /**
+     * Requests a translation for the provided {@link TranslationRequest} using the Translator's
+     * source spec and destination spec.
+     *
+     * <p><strong>NOTE: </strong>Call on a worker thread.
+     *
+     * @param request {@link TranslationRequest} request to be translated.
+     *
+     * @return {@link TranslationRequest} containing translated request,
+     *         or null if translation could not be done.
+     * @throws IllegalStateException if this TextClassification session was destroyed when calls
+     */
+    @Nullable
+    @WorkerThread
+    public TranslationResponse translate(@NonNull TranslationRequest request) {
+        Objects.requireNonNull(request, "Translation request cannot be null");
+        if (isDestroyed()) {
+            // TODO(b/176464808): Disallow multiple Translator now, it will throw
+            //  IllegalStateException. Need to discuss if we can allow multiple Translators.
+            throw new IllegalStateException(
+                    "This translator has been destroyed");
+        }
+        final ArrayList<TranslationRequest> requests = new ArrayList<>();
+        requests.add(request);
+        final android.service.translation.TranslationRequest internalRequest =
+                new android.service.translation.TranslationRequest
+                        .Builder(getNextRequestId(), mSourceSpec, mDestSpec, requests)
+                        .build();
+
+        TranslationResponse response = null;
+        try {
+            final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
+            mDirectServiceBinder.onTranslationRequest(internalRequest, mId, null, receiver);
+
+            response = receiver.getParcelableResult();
+        } catch (RemoteException e) {
+            Log.w(TAG, "RemoteException calling requestTranslate(): " + e);
+        }  catch (SyncResultReceiver.TimeoutException e) {
+            Log.e(TAG, "Timed out calling requestTranslate: " + e);
+        }
+        if (sDEBUG) {
+            Log.v(TAG, "Receive translation response: " + response);
+        }
+        return response;
+    }
+
+    /**
+     * Destroy this Translator.
+     */
+    public void destroy() {
+        synchronized (mLock) {
+            if (mDestroyed) {
+                return;
+            }
+            mDestroyed = true;
+            try {
+                mDirectServiceBinder.onFinishTranslationSession(mId);
+            } catch (RemoteException e) {
+                Log.w(TAG, "RemoteException calling onSessionFinished");
+            }
+            mDirectServiceBinder = null;
+            mManager.removeTranslator(mId);
+        }
+    }
+
+    /**
+     * Returns whether or not this Translator has been destroyed.
+     *
+     * @see #destroy()
+     */
+    public boolean isDestroyed() {
+        synchronized (mLock) {
+            return mDestroyed;
+        }
+    }
+
+    // TODO: add methods for UI-toolkit case.
+}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 0025d1e..26dd5e3 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -99,6 +99,7 @@
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.MotionEvent;
+import android.view.OnReceiveContentListener;
 import android.view.SubMenu;
 import android.view.View;
 import android.view.View.DragShadowBuilder;
@@ -588,8 +589,18 @@
         mUndoOwner = mUndoManager.getOwner(UNDO_OWNER_TAG, this);
     }
 
-    @VisibleForTesting
-    public @NonNull TextViewOnReceiveContentListener getDefaultOnReceiveContentListener() {
+    /**
+     * Returns the default handler for receiving content in an editable {@link TextView}. This
+     * listener impl is used to encapsulate the default behavior but it is not part of the public
+     * API. If an app wants to execute the default platform behavior for receiving content, it
+     * should call {@link View#onReceiveContent}. Alternatively, if an app implements a custom
+     * listener for receiving content and wants to delegate some of the content to be handled by
+     * the platform, it should return the corresponding content from its listener. See
+     * {@link View#setOnReceiveContentListener} and {@link OnReceiveContentListener} for more info.
+     */
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+    @NonNull
+    public TextViewOnReceiveContentListener getDefaultOnReceiveContentListener() {
         return mDefaultOnReceiveContentListener;
     }
 
@@ -6613,6 +6624,9 @@
                     }
 
                     updateSelection(event);
+                    if (mTextView.hasSelection() && mEndHandle != null) {
+                        mEndHandle.updateMagnifier(event);
+                    }
                     break;
 
                 case MotionEvent.ACTION_UP:
@@ -6623,6 +6637,9 @@
                         break;
                     }
                     updateSelection(event);
+                    if (mEndHandle != null) {
+                        mEndHandle.dismissMagnifier();
+                    }
 
                     // No longer dragging to select text, let the parent intercept events.
                     mTextView.getParent().requestDisallowInterceptTouchEvent(false);
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 220a31c..8dafc5d 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -75,6 +75,8 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroup.MarginLayoutParams;
+import android.view.ViewManager;
+import android.view.ViewParent;
 import android.view.ViewStub;
 import android.widget.AdapterView.OnItemClickListener;
 
@@ -177,6 +179,7 @@
     private static final int OVERRIDE_TEXT_COLORS_TAG = 20;
     private static final int SET_RIPPLE_DRAWABLE_COLOR_TAG = 21;
     private static final int SET_INT_TAG_TAG = 22;
+    private static final int REMOVE_FROM_PARENT_ACTION_TAG = 23;
 
     /** @hide **/
     @IntDef(prefix = "MARGIN_", value = {
@@ -1831,6 +1834,75 @@
     }
 
     /**
+     * Action to remove a view from its parent.
+     */
+    private class RemoveFromParentAction extends Action {
+
+        RemoveFromParentAction(@IdRes int viewId) {
+            this.viewId = viewId;
+        }
+
+        RemoveFromParentAction(Parcel parcel) {
+            viewId = parcel.readInt();
+        }
+
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(viewId);
+        }
+
+        @Override
+        public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
+            final View target = root.findViewById(viewId);
+
+            if (target == null || target == root) {
+                return;
+            }
+
+            ViewParent parent = target.getParent();
+            if (parent instanceof ViewManager) {
+                ((ViewManager) parent).removeView(target);
+            }
+        }
+
+        @Override
+        public Action initActionAsync(ViewTree root, ViewGroup rootParent, OnClickHandler handler) {
+            // In the async implementation, update the view tree so that subsequent calls to
+            // findViewById return the correct view.
+            root.createTree();
+            ViewTree target = root.findViewTreeById(viewId);
+
+            if (target == null || target == root) {
+                return ACTION_NOOP;
+            }
+
+            ViewTree parent = root.findViewTreeParentOf(target);
+            if (parent == null || !(parent.mRoot instanceof ViewManager)) {
+                return ACTION_NOOP;
+            }
+            final ViewManager parentVg = (ViewManager) parent.mRoot;
+
+            parent.mChildren.remove(target);
+            return new RuntimeAction() {
+                @Override
+                public void apply(View root, ViewGroup rootParent, OnClickHandler handler)
+                        throws ActionException {
+                    parentVg.removeView(target.mRoot);
+                }
+            };
+        }
+
+        @Override
+        public int getActionTag() {
+            return REMOVE_FROM_PARENT_ACTION_TAG;
+        }
+
+        @Override
+        public int mergeBehavior() {
+            return MERGE_APPEND;
+        }
+    }
+
+    /**
      * Helper action to set compound drawables on a TextView. Supports relative
      * (s/t/e/b) or cardinal (l/t/r/b) arrangement.
      */
@@ -2537,6 +2609,8 @@
                 return new SetRippleDrawableColor(parcel);
             case SET_INT_TAG_TAG:
                 return new SetIntTagAction(parcel);
+            case REMOVE_FROM_PARENT_ACTION_TAG:
+                return new RemoveFromParentAction(parcel);
             default:
                 throw new ActionException("Tag " + tag + " not found");
         }
@@ -2675,6 +2749,18 @@
     }
 
     /**
+     * Removes the {@link View} specified by the {@code viewId} from its parent {@link ViewManager}.
+     * This will do nothing if the viewId specifies the root view of this RemoteViews.
+     *
+     * @param viewId The id of the {@link View} to remove from its parent.
+     *
+     * @hide
+     */
+    public void removeFromParent(@IdRes int viewId) {
+        addAction(new RemoveFromParentAction(viewId));
+    }
+
+    /**
      * Equivalent to calling {@link AdapterViewAnimator#showNext()}
      *
      * @param viewId The id of the view on which to call {@link AdapterViewAnimator#showNext()}
@@ -4025,6 +4111,22 @@
             return null;
         }
 
+        public ViewTree findViewTreeParentOf(ViewTree child) {
+            if (mChildren == null) {
+                return null;
+            }
+            for (ViewTree tree : mChildren) {
+                if (tree == child) {
+                    return this;
+                }
+                ViewTree result = tree.findViewTreeParentOf(child);
+                if (result != null) {
+                    return result;
+                }
+            }
+            return null;
+        }
+
         public void replaceView(View v) {
             mRoot = v;
             mChildren = null;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 1599f2b..b866025 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -11717,6 +11717,18 @@
                     }
                 }
             }
+            String[] mimeTypes = getOnReceiveContentMimeTypes();
+            if (mimeTypes == null && mEditor != null) {
+                // If the app hasn't set a listener for receiving content on this view (ie,
+                // getOnReceiveContentMimeTypes() returns null), check if it implements the
+                // keyboard image API and, if possible, use those MIME types as fallback.
+                // This fallback is only in place for autofill, not other mechanisms for
+                // inserting content. See AUTOFILL_NON_TEXT_REQUIRES_ON_RECEIVE_CONTENT_LISTENER
+                // in TextViewOnReceiveContentListener for more info.
+                mimeTypes = mEditor.getDefaultOnReceiveContentListener()
+                        .getFallbackMimeTypesForAutofill(this);
+            }
+            structure.setOnReceiveContentMimeTypes(mimeTypes);
         }
 
         if (!isPassword || viewFor == VIEW_STRUCTURE_FOR_AUTOFILL
diff --git a/core/java/android/widget/TextViewOnReceiveContentListener.java b/core/java/android/widget/TextViewOnReceiveContentListener.java
index 8cef106..91fac55 100644
--- a/core/java/android/widget/TextViewOnReceiveContentListener.java
+++ b/core/java/android/widget/TextViewOnReceiveContentListener.java
@@ -60,7 +60,7 @@
  *
  * @hide
  */
-@VisibleForTesting
+@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
 public final class TextViewOnReceiveContentListener implements OnReceiveContentListener {
     private static final String LOG_TAG = "ReceiveContent";
 
@@ -261,10 +261,17 @@
         mInputConnectionInfo = null;
     }
 
-    /** @hide */
-    @VisibleForTesting
+    /**
+     * Returns the MIME types accepted by {@link View#performReceiveContent} for the given view,
+     * <strong>for autofill purposes</strong>. This will be non-null only if fallback to the
+     * keyboard image API {@link #isUsageOfImeCommitContentEnabled is enabled} and the view has an
+     * {@link InputConnection} with {@link EditorInfo#contentMimeTypes} populated.
+     *
+     * @hide
+     */
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
     @Nullable
-    public String[] getEditorInfoMimeTypes(@NonNull TextView view) {
+    public String[] getFallbackMimeTypesForAutofill(@NonNull TextView view) {
         if (!isUsageOfImeCommitContentEnabled(view)) {
             return null;
         }
diff --git a/core/java/com/android/internal/inputmethod/Completable.java b/core/java/com/android/internal/inputmethod/Completable.java
index b82ba81..d6a4663 100644
--- a/core/java/com/android/internal/inputmethod/Completable.java
+++ b/core/java/com/android/internal/inputmethod/Completable.java
@@ -117,8 +117,8 @@
         }
 
         /**
-         * @return {@link true} if {@link #onComplete()} gets called and {@link #mState} is
-         *         {@link CompletionState#COMPLETED_WITH_VALUE} .
+         * @return {@code true} if {@link #onComplete()} gets called and {@link #mState} is
+         *         {@link CompletionState#COMPLETED_WITH_VALUE}.
          */
         @AnyThread
         public boolean hasValue() {
@@ -232,13 +232,25 @@
         }
 
         /**
-         * Blocks the calling thread until this object becomes ready to return the value.
+         * Blocks the calling thread until this object becomes ready to return the value, even if
+         * {@link InterruptedException} is thrown.
          */
         @AnyThread
         public void await() {
-            try {
-                mLatch.await();
-            } catch (InterruptedException ignored) { }
+            boolean interrupted = false;
+            while (true) {
+                try {
+                    mLatch.await();
+                    break;
+                } catch (InterruptedException ignored) {
+                    interrupted = true;
+                }
+            }
+
+            if (interrupted) {
+                // Try to preserve the interrupt bit on this thread.
+                Thread.currentThread().interrupt();
+            }
         }
     }
 
@@ -487,7 +499,7 @@
     /**
      * Await the result by the {@link Completable.Values}.
      *
-     * @return the result once {@link ValueBase#onComplete()}
+     * @return the result once {@link ValueBase#onComplete()}.
      */
     @AnyThread
     @Nullable
@@ -499,7 +511,7 @@
     /**
      * Await the int result by the {@link Completable.Int}.
      *
-     * @return the result once {@link ValueBase#onComplete()}
+     * @return the result once {@link ValueBase#onComplete()}.
      */
     @AnyThread
     public static int getIntResult(@NonNull Completable.Int value) {
diff --git a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java
index 9c3bb76..6609ebe 100644
--- a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java
+++ b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java
@@ -16,7 +16,11 @@
 
 package com.android.internal.os;
 
+import android.os.BatteryConsumer;
 import android.os.BatteryStats;
+import android.os.BatteryUsageStats;
+import android.os.BatteryUsageStatsQuery;
+import android.os.SystemBatteryConsumer;
 import android.os.UserHandle;
 import android.util.SparseArray;
 
@@ -26,11 +30,30 @@
  * Estimates power consumed by the ambient display
  */
 public class AmbientDisplayPowerCalculator extends PowerCalculator {
-
-    private final PowerProfile mPowerProfile;
+    private final UsageBasedPowerEstimator mPowerEstimator;
 
     public AmbientDisplayPowerCalculator(PowerProfile powerProfile) {
-        mPowerProfile = powerProfile;
+        mPowerEstimator = new UsageBasedPowerEstimator(
+                powerProfile.getAveragePower(PowerProfile.POWER_AMBIENT_DISPLAY));
+    }
+
+    /**
+     * Ambient display power is the additional power the screen takes while in ambient display/
+     * screen doze/always-on display (interchangeable terms) mode.
+     */
+    @Override
+    public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
+            long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query,
+            SparseArray<UserHandle> asUsers) {
+        final long durationMs = calculateDuration(batteryStats, rawRealtimeUs,
+                BatteryStats.STATS_SINCE_CHARGED);
+        final double powerMah = mPowerEstimator.calculatePower(durationMs);
+        if (powerMah > 0) {
+            builder.getOrCreateSystemBatteryConsumerBuilder(
+                    SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY)
+                    .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, powerMah)
+                    .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE, durationMs);
+        }
     }
 
     /**
@@ -42,16 +65,18 @@
     @Override
     public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
             long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
-
-        long ambientDisplayMs = batteryStats.getScreenDozeTime(rawRealtimeUs, statsType) / 1000;
-        double power = mPowerProfile.getAveragePower(PowerProfile.POWER_AMBIENT_DISPLAY)
-                * ambientDisplayMs / (60 * 60 * 1000);
-        if (power > 0) {
+        final long durationMs = calculateDuration(batteryStats, rawRealtimeUs, statsType);
+        final double powerMah = mPowerEstimator.calculatePower(durationMs);
+        if (powerMah > 0) {
             BatterySipper bs = new BatterySipper(BatterySipper.DrainType.AMBIENT_DISPLAY, null, 0);
-            bs.usagePowerMah = power;
-            bs.usageTimeMs = ambientDisplayMs;
+            bs.usagePowerMah = powerMah;
+            bs.usageTimeMs = durationMs;
             bs.sumPower();
             sippers.add(bs);
         }
     }
+
+    private long calculateDuration(BatteryStats batteryStats, long rawRealtimeUs, int statsType) {
+        return batteryStats.getScreenDozeTime(rawRealtimeUs, statsType) / 1000;
+    }
 }
diff --git a/core/java/com/android/internal/os/AudioPowerCalculator.java b/core/java/com/android/internal/os/AudioPowerCalculator.java
new file mode 100644
index 0000000..79b331d
--- /dev/null
+++ b/core/java/com/android/internal/os/AudioPowerCalculator.java
@@ -0,0 +1,48 @@
+/*
+ * 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.internal.os;
+
+import android.os.BatteryConsumer;
+import android.os.BatteryStats;
+import android.os.BatteryUsageStatsQuery;
+import android.os.UidBatteryConsumer;
+
+/**
+ * A {@link PowerCalculator} to calculate power consumed by audio hardware.
+ *
+ * Also see {@link PowerProfile#POWER_AUDIO}.
+ */
+public class AudioPowerCalculator extends PowerCalculator {
+    // Calculate audio power usage, an estimate based on the average power routed to different
+    // components like speaker, bluetooth, usb-c, earphone, etc.
+    // TODO(b/175344313): improve the model by taking into account different audio routes
+    private final UsageBasedPowerEstimator mPowerEstimator;
+
+    public AudioPowerCalculator(PowerProfile powerProfile) {
+        mPowerEstimator = new UsageBasedPowerEstimator(
+                powerProfile.getAveragePower(PowerProfile.POWER_AUDIO));
+    }
+
+    @Override
+    protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
+            long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
+        final long durationMs = mPowerEstimator.calculateDuration(u.getAudioTurnedOnTimer(),
+                rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED);
+        final double powerMah = mPowerEstimator.calculatePower(durationMs);
+        app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_AUDIO, durationMs)
+                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_AUDIO, powerMah);
+    }
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 93dff9f..33aa190 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -873,7 +873,9 @@
     protected StopwatchTimer mScreenDozeTimer;
 
     int mScreenBrightnessBin = -1;
-    final StopwatchTimer[] mScreenBrightnessTimer = new StopwatchTimer[NUM_SCREEN_BRIGHTNESS_BINS];
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+    protected final StopwatchTimer[] mScreenBrightnessTimer =
+            new StopwatchTimer[NUM_SCREEN_BRIGHTNESS_BINS];
 
     boolean mPretendScreenOff;
 
diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
index 9904d30..e5d64a0 100644
--- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
+++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
@@ -66,7 +66,8 @@
                         mContext.getSystemService(SensorManager.class)));
                 mPowerCalculators.add(new CameraPowerCalculator(mPowerProfile));
                 mPowerCalculators.add(new FlashlightPowerCalculator(mPowerProfile));
-                mPowerCalculators.add(new MediaPowerCalculator(mPowerProfile));
+                mPowerCalculators.add(new AudioPowerCalculator(mPowerProfile));
+                mPowerCalculators.add(new VideoPowerCalculator(mPowerProfile));
                 mPowerCalculators.add(new PhonePowerCalculator(mPowerProfile));
                 mPowerCalculators.add(new ScreenPowerCalculator(mPowerProfile));
                 mPowerCalculators.add(new AmbientDisplayPowerCalculator(mPowerProfile));
diff --git a/core/java/com/android/internal/os/BluetoothPowerCalculator.java b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
index f5690e0..4c3b950 100644
--- a/core/java/com/android/internal/os/BluetoothPowerCalculator.java
+++ b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
@@ -29,8 +29,8 @@
 import java.util.List;
 
 public class BluetoothPowerCalculator extends PowerCalculator {
-    private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
     private static final String TAG = "BluetoothPowerCalc";
+    private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
     private final double mIdleMa;
     private final double mRxMa;
     private final double mTxMa;
@@ -41,11 +41,6 @@
         public double powerMah;
     }
 
-    // Objects used for passing calculation results. Fields are used to avoid allocations.
-    private final PowerAndDuration mUidPowerAndDuration = new PowerAndDuration();
-    private final PowerAndDuration mTotalPowerAndDuration = new PowerAndDuration();
-    private final PowerAndDuration mSystemPowerAndDuration = new PowerAndDuration();
-
     public BluetoothPowerCalculator(PowerProfile profile) {
         mIdleMa = profile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE);
         mRxMa = profile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_RX);
@@ -61,8 +56,7 @@
             return;
         }
 
-        mTotalPowerAndDuration.durationMs = 0;
-        mTotalPowerAndDuration.powerMah = 0;
+        final PowerAndDuration total = new PowerAndDuration();
 
         SystemBatteryConsumer.Builder systemBatteryConsumerBuilder =
                 builder.getOrCreateSystemBatteryConsumerBuilder(
@@ -72,24 +66,25 @@
                 builder.getUidBatteryConsumerBuilders();
         for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
             final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
-            calculateApp(app);
+            calculateApp(app, total);
             if (app.getUid() == Process.BLUETOOTH_UID) {
                 app.setSystemComponent(true);
                 systemBatteryConsumerBuilder.addUidBatteryConsumer(app);
             }
         }
 
-        final BatteryStats.ControllerActivityCounter counter =
+        final BatteryStats.ControllerActivityCounter activityCounter =
                 batteryStats.getBluetoothControllerActivity();
-
-        calculatePowerAndDuration(counter, mSystemPowerAndDuration);
+        final long systemDurationMs = calculateDuration(activityCounter);
+        final double systemPowerMah = calculatePower(activityCounter);
 
         // Subtract what the apps used, but clamp to 0.
-        final long systemComponentDurationMs = Math.max(0,
-                mSystemPowerAndDuration.durationMs - mTotalPowerAndDuration.durationMs);
-        final double systemComponentPowerMah = Math.max(0,
-                mSystemPowerAndDuration.powerMah - mTotalPowerAndDuration.powerMah);
-
+        final long systemComponentDurationMs = Math.max(0, systemDurationMs - total.durationMs);
+        final double systemComponentPowerMah = Math.max(0, systemPowerMah - total.powerMah);
+        if (DEBUG && systemComponentPowerMah != 0) {
+            Log.d(TAG, "Bluetooth active: time=" + (systemComponentDurationMs)
+                    + " power=" + formatCharge(systemComponentPowerMah));
+        }
         systemBatteryConsumerBuilder
                 .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_BLUETOOTH,
                         systemComponentDurationMs)
@@ -97,17 +92,17 @@
                         systemComponentPowerMah);
     }
 
-    private void calculateApp(UidBatteryConsumer.Builder app) {
-        calculatePowerAndDuration(app.getBatteryStatsUid().getBluetoothControllerActivity(),
-                mUidPowerAndDuration);
+    private void calculateApp(UidBatteryConsumer.Builder app, PowerAndDuration total) {
+        final BatteryStats.ControllerActivityCounter activityCounter =
+                app.getBatteryStatsUid().getBluetoothControllerActivity();
+        final long durationMs = calculateDuration(activityCounter);
+        final double powerMah = calculatePower(activityCounter);
 
-        app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_BLUETOOTH,
-                mUidPowerAndDuration.durationMs)
-                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
-                        mUidPowerAndDuration.powerMah);
+        app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_BLUETOOTH, durationMs)
+                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_BLUETOOTH, powerMah);
 
-        mTotalPowerAndDuration.powerMah += mUidPowerAndDuration.powerMah;
-        mTotalPowerAndDuration.durationMs += mUidPowerAndDuration.durationMs;
+        total.durationMs += durationMs;
+        total.powerMah += powerMah;
     }
 
     @Override
@@ -117,20 +112,24 @@
             return;
         }
 
-        mTotalPowerAndDuration.durationMs = 0;
-        mTotalPowerAndDuration.powerMah = 0;
+        PowerAndDuration total = new PowerAndDuration();
 
-        super.calculate(sippers, batteryStats, rawRealtimeUs, rawUptimeUs, statsType, asUsers);
+        for (int i = sippers.size() - 1; i >= 0; i--) {
+            final BatterySipper app = sippers.get(i);
+            if (app.drainType == BatterySipper.DrainType.APP) {
+                calculateApp(app, app.uidObj, statsType, total);
+            }
+        }
 
         BatterySipper bs = new BatterySipper(BatterySipper.DrainType.BLUETOOTH, null, 0);
-        calculatePowerAndDuration(batteryStats.getBluetoothControllerActivity(),
-                mSystemPowerAndDuration);
+        final BatteryStats.ControllerActivityCounter activityCounter =
+                batteryStats.getBluetoothControllerActivity();
+        final double systemPowerMah = calculatePower(activityCounter);
+        final long systemDurationMs = calculateDuration(activityCounter);
 
         // Subtract what the apps used, but clamp to 0.
-        double powerMah =
-                Math.max(0, mSystemPowerAndDuration.powerMah - mTotalPowerAndDuration.powerMah);
-        final long durationMs =
-                Math.max(0, mSystemPowerAndDuration.durationMs - mTotalPowerAndDuration.durationMs);
+        final double powerMah = Math.max(0, systemPowerMah - total.powerMah);
+        final long durationMs = Math.max(0, systemDurationMs - total.durationMs);
         if (DEBUG && powerMah != 0) {
             Log.d(TAG, "Bluetooth active: time=" + (durationMs)
                     + " power=" + formatCharge(powerMah));
@@ -152,27 +151,43 @@
         }
     }
 
-    @Override
-    protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
-                             long rawUptimeUs, int statsType) {
+    private void calculateApp(BatterySipper app, BatteryStats.Uid u, int statsType,
+            PowerAndDuration total) {
+        final BatteryStats.ControllerActivityCounter activityCounter =
+                u.getBluetoothControllerActivity();
+        final long durationMs = calculateDuration(activityCounter);
+        final double powerMah = calculatePower(activityCounter);
 
-        calculatePowerAndDuration(u.getBluetoothControllerActivity(), mUidPowerAndDuration);
-
-        app.bluetoothPowerMah = mUidPowerAndDuration.powerMah;
-        app.bluetoothRunningTimeMs = mUidPowerAndDuration.durationMs;
+        app.bluetoothRunningTimeMs = durationMs;
+        app.bluetoothPowerMah = powerMah;
         app.btRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_BT_RX_DATA, statsType);
         app.btTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_BT_TX_DATA, statsType);
 
-        mTotalPowerAndDuration.powerMah += mUidPowerAndDuration.powerMah;
-        mTotalPowerAndDuration.durationMs += mUidPowerAndDuration.durationMs;
+        total.durationMs += durationMs;
+        total.powerMah += powerMah;
     }
 
-    private void calculatePowerAndDuration(BatteryStats.ControllerActivityCounter counter,
-            PowerAndDuration powerAndDuration) {
+    private long calculateDuration(BatteryStats.ControllerActivityCounter counter) {
         if (counter == null) {
-            powerAndDuration.durationMs = 0;
-            powerAndDuration.powerMah = 0;
-            return;
+            return 0;
+        }
+
+        return counter.getIdleTimeCounter().getCountLocked(BatteryStats.STATS_SINCE_CHARGED)
+                + counter.getRxTimeCounter().getCountLocked(BatteryStats.STATS_SINCE_CHARGED)
+                + counter.getTxTimeCounters()[0].getCountLocked(BatteryStats.STATS_SINCE_CHARGED);
+    }
+
+    private double calculatePower(BatteryStats.ControllerActivityCounter counter) {
+        if (counter == null) {
+            return 0;
+        }
+
+        final double powerMah =
+                counter.getPowerCounter().getCountLocked(BatteryStats.STATS_SINCE_CHARGED)
+                        / (double) (1000 * 60 * 60);
+
+        if (powerMah != 0) {
+            return powerMah;
         }
 
         final long idleTimeMs =
@@ -181,17 +196,7 @@
                 counter.getRxTimeCounter().getCountLocked(BatteryStats.STATS_SINCE_CHARGED);
         final long txTimeMs =
                 counter.getTxTimeCounters()[0].getCountLocked(BatteryStats.STATS_SINCE_CHARGED);
-        final long totalTimeMs = idleTimeMs + txTimeMs + rxTimeMs;
-        double powerMah =
-                counter.getPowerCounter().getCountLocked(BatteryStats.STATS_SINCE_CHARGED)
-                        / (double) (1000 * 60 * 60);
-
-        if (powerMah == 0) {
-            powerMah = ((idleTimeMs * mIdleMa) + (rxTimeMs * mRxMa) + (txTimeMs * mTxMa))
-                    / (1000 * 60 * 60);
-        }
-
-        powerAndDuration.durationMs = totalTimeMs;
-        powerAndDuration.powerMah = powerMah;
+        return ((idleTimeMs * mIdleMa) + (rxTimeMs * mRxMa) + (txTimeMs * mTxMa))
+                / (1000 * 60 * 60);
     }
 }
diff --git a/core/java/com/android/internal/os/CameraPowerCalculator.java b/core/java/com/android/internal/os/CameraPowerCalculator.java
index 0365d9e..6f8e927 100644
--- a/core/java/com/android/internal/os/CameraPowerCalculator.java
+++ b/core/java/com/android/internal/os/CameraPowerCalculator.java
@@ -15,7 +15,10 @@
  */
 package com.android.internal.os;
 
+import android.os.BatteryConsumer;
 import android.os.BatteryStats;
+import android.os.BatteryUsageStatsQuery;
+import android.os.UidBatteryConsumer;
 
 /**
  * Power calculator for the camera subsystem, excluding the flashlight.
@@ -23,26 +26,33 @@
  * Note: Power draw for the flash unit should be included in the FlashlightPowerCalculator.
  */
 public class CameraPowerCalculator extends PowerCalculator {
-    private final double mCameraPowerOnAvg;
+    // Calculate camera power usage.  Right now, this is a (very) rough estimate based on the
+    // average power usage for a typical camera application.
+    private final UsageBasedPowerEstimator mPowerEstimator;
 
     public CameraPowerCalculator(PowerProfile profile) {
-        mCameraPowerOnAvg = profile.getAveragePower(PowerProfile.POWER_CAMERA);
+        mPowerEstimator = new UsageBasedPowerEstimator(
+                profile.getAveragePower(PowerProfile.POWER_CAMERA));
+    }
+
+    @Override
+    protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
+            long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
+        final long durationMs =
+                mPowerEstimator.calculateDuration(u.getCameraTurnedOnTimer(), rawRealtimeUs,
+                        BatteryStats.STATS_SINCE_CHARGED);
+        final double powerMah = mPowerEstimator.calculatePower(durationMs);
+        app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CAMERA, durationMs)
+                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA, powerMah);
     }
 
     @Override
     protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
-                             long rawUptimeUs, int statsType) {
-
-        // Calculate camera power usage.  Right now, this is a (very) rough estimate based on the
-        // average power usage for a typical camera application.
-        final BatteryStats.Timer timer = u.getCameraTurnedOnTimer();
-        if (timer != null) {
-            final long totalTime = timer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000;
-            app.cameraTimeMs = totalTime;
-            app.cameraPowerMah = (totalTime * mCameraPowerOnAvg) / (1000*60*60);
-        } else {
-            app.cameraTimeMs = 0;
-            app.cameraPowerMah = 0;
-        }
+            long rawUptimeUs, int statsType) {
+        final long durationMs = mPowerEstimator.calculateDuration(u.getCameraTurnedOnTimer(),
+                rawRealtimeUs, statsType);
+        final double powerMah = mPowerEstimator.calculatePower(durationMs);
+        app.cameraTimeMs = durationMs;
+        app.cameraPowerMah = powerMah;
     }
 }
diff --git a/core/java/com/android/internal/os/FlashlightPowerCalculator.java b/core/java/com/android/internal/os/FlashlightPowerCalculator.java
index 330feef..6c29a91 100644
--- a/core/java/com/android/internal/os/FlashlightPowerCalculator.java
+++ b/core/java/com/android/internal/os/FlashlightPowerCalculator.java
@@ -15,32 +15,41 @@
  */
 package com.android.internal.os;
 
+import android.os.BatteryConsumer;
 import android.os.BatteryStats;
+import android.os.BatteryUsageStatsQuery;
+import android.os.UidBatteryConsumer;
 
 /**
  * Power calculator for the flashlight.
  */
 public class FlashlightPowerCalculator extends PowerCalculator {
-    private final double mFlashlightPowerOnAvg;
+    // Calculate flashlight power usage.  Right now, this is based on the average power draw
+    // of the flash unit when kept on over a short period of time.
+    private final UsageBasedPowerEstimator mPowerEstimator;
 
     public FlashlightPowerCalculator(PowerProfile profile) {
-        mFlashlightPowerOnAvg = profile.getAveragePower(PowerProfile.POWER_FLASHLIGHT);
+        mPowerEstimator = new UsageBasedPowerEstimator(
+                profile.getAveragePower(PowerProfile.POWER_FLASHLIGHT));
+    }
+
+    @Override
+    protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
+            long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
+        final long durationMs = mPowerEstimator.calculateDuration(u.getFlashlightTurnedOnTimer(),
+                rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED);
+        final double powerMah = mPowerEstimator.calculatePower(durationMs);
+        app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_FLASHLIGHT, durationMs)
+                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT, powerMah);
     }
 
     @Override
     protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
-                             long rawUptimeUs, int statsType) {
-
-        // Calculate flashlight power usage.  Right now, this is based on the average power draw
-        // of the flash unit when kept on over a short period of time.
-        final BatteryStats.Timer timer = u.getFlashlightTurnedOnTimer();
-        if (timer != null) {
-            final long totalTime = timer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000;
-            app.flashlightTimeMs = totalTime;
-            app.flashlightPowerMah = (totalTime * mFlashlightPowerOnAvg) / (1000*60*60);
-        } else {
-            app.flashlightTimeMs = 0;
-            app.flashlightPowerMah = 0;
-        }
+            long rawUptimeUs, int statsType) {
+        final long durationMs = mPowerEstimator.calculateDuration(u.getFlashlightTurnedOnTimer(),
+                rawRealtimeUs, statsType);
+        final double powerMah = mPowerEstimator.calculatePower(durationMs);
+        app.flashlightTimeMs = durationMs;
+        app.flashlightPowerMah = powerMah;
     }
 }
diff --git a/core/java/com/android/internal/os/IdlePowerCalculator.java b/core/java/com/android/internal/os/IdlePowerCalculator.java
index 44ad344..dcc8a15 100644
--- a/core/java/com/android/internal/os/IdlePowerCalculator.java
+++ b/core/java/com/android/internal/os/IdlePowerCalculator.java
@@ -16,7 +16,11 @@
 
 package com.android.internal.os;
 
+import android.os.BatteryConsumer;
 import android.os.BatteryStats;
+import android.os.BatteryUsageStats;
+import android.os.BatteryUsageStatsQuery;
+import android.os.SystemBatteryConsumer;
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.SparseArray;
@@ -29,46 +33,70 @@
 public class IdlePowerCalculator extends PowerCalculator {
     private static final String TAG = "IdlePowerCalculator";
     private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
-    private final PowerProfile mPowerProfile;
+    private final double mAveragePowerCpuSuspendMahPerUs;
+    private final double mAveragePowerCpuIdleMahPerUs;
+    public long mDurationMs;
+    public double mPowerMah;
 
     public IdlePowerCalculator(PowerProfile powerProfile) {
-        mPowerProfile = powerProfile;
+        mAveragePowerCpuSuspendMahPerUs =
+                powerProfile.getAveragePower(PowerProfile.POWER_CPU_SUSPEND)
+                        / (60 * 60 * 1_000_000.0);
+        mAveragePowerCpuIdleMahPerUs =
+                powerProfile.getAveragePower(PowerProfile.POWER_CPU_IDLE)
+                        / (60 * 60 * 1_000_000.0);
     }
 
-    /**
-     * Calculate the baseline power usage for the device when it is in suspend and idle.
-     * The device is drawing POWER_CPU_SUSPEND power at its lowest power state.
-     * The device is drawing POWER_CPU_SUSPEND + POWER_CPU_IDLE power when a wakelock is held.
-     */
+    @Override
+    public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
+            long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query,
+            SparseArray<UserHandle> asUsers) {
+        calculatePowerAndDuration(batteryStats, rawRealtimeUs, rawUptimeUs,
+                BatteryStats.STATS_SINCE_CHARGED);
+        if (mPowerMah != 0) {
+            builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_IDLE)
+                    .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, mPowerMah)
+                    .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE, mDurationMs);
+        }
+    }
+
     @Override
     public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
             long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
-        long batteryUptimeUs = batteryStats.computeBatteryUptime(rawUptimeUs, statsType);
-        long batteryRealtimeUs = batteryStats.computeBatteryRealtime(rawRealtimeUs, statsType);
+        calculatePowerAndDuration(batteryStats, rawRealtimeUs, rawUptimeUs, statsType);
 
+        if (mPowerMah != 0) {
+            BatterySipper bs = new BatterySipper(BatterySipper.DrainType.IDLE, null, 0);
+            bs.usagePowerMah = mPowerMah;
+            bs.usageTimeMs = mDurationMs;
+            bs.sumPower();
+            sippers.add(bs);
+        }
+    }
+
+    /**
+     * Calculates the baseline power usage for the device when it is in suspend and idle.
+     * The device is drawing POWER_CPU_SUSPEND power at its lowest power state.
+     * The device is drawing POWER_CPU_SUSPEND + POWER_CPU_IDLE power when a wakelock is held.
+     */
+    private void calculatePowerAndDuration(BatteryStats batteryStats, long rawRealtimeUs,
+            long rawUptimeUs, int statsType) {
+        long batteryRealtimeUs = batteryStats.computeBatteryRealtime(rawRealtimeUs, statsType);
+        long batteryUptimeUs = batteryStats.computeBatteryUptime(rawUptimeUs, statsType);
         if (DEBUG) {
             Log.d(TAG, "Battery type time: realtime=" + (batteryRealtimeUs / 1000) + " uptime="
                     + (batteryUptimeUs / 1000));
         }
 
-        final double suspendPowerMaMs = (batteryRealtimeUs / 1000)
-                * mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_SUSPEND);
-        final double idlePowerMaMs = (batteryUptimeUs / 1000)
-                * mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_IDLE);
-        final double totalPowerMah = (suspendPowerMaMs + idlePowerMaMs) / (60 * 60 * 1000);
-        if (DEBUG && totalPowerMah != 0) {
+        final double suspendPowerMah = batteryRealtimeUs * mAveragePowerCpuSuspendMahPerUs;
+        final double idlePowerMah = batteryUptimeUs * mAveragePowerCpuIdleMahPerUs;
+        mPowerMah = suspendPowerMah + idlePowerMah;
+        if (DEBUG && mPowerMah != 0) {
             Log.d(TAG, "Suspend: time=" + (batteryRealtimeUs / 1000)
-                    + " power=" + formatCharge(suspendPowerMaMs / (60 * 60 * 1000)));
+                    + " power=" + formatCharge(suspendPowerMah));
             Log.d(TAG, "Idle: time=" + (batteryUptimeUs / 1000)
-                    + " power=" + formatCharge(idlePowerMaMs / (60 * 60 * 1000)));
+                    + " power=" + formatCharge(idlePowerMah));
         }
-
-        if (totalPowerMah != 0) {
-            BatterySipper bs = new BatterySipper(BatterySipper.DrainType.IDLE, null, 0);
-            bs.usagePowerMah = totalPowerMah;
-            bs.usageTimeMs = batteryRealtimeUs / 1000;
-            bs.sumPower();
-            sippers.add(bs);
-        }
+        mDurationMs = batteryRealtimeUs / 1000;
     }
 }
diff --git a/core/java/com/android/internal/os/MemoryPowerCalculator.java b/core/java/com/android/internal/os/MemoryPowerCalculator.java
index 10d9b65..df46058 100644
--- a/core/java/com/android/internal/os/MemoryPowerCalculator.java
+++ b/core/java/com/android/internal/os/MemoryPowerCalculator.java
@@ -1,64 +1,75 @@
 package com.android.internal.os;
 
+import android.os.BatteryConsumer;
 import android.os.BatteryStats;
+import android.os.BatteryUsageStats;
+import android.os.BatteryUsageStatsQuery;
+import android.os.SystemBatteryConsumer;
 import android.os.UserHandle;
-import android.util.Log;
 import android.util.LongSparseArray;
 import android.util.SparseArray;
 
 import java.util.List;
 
 public class MemoryPowerCalculator extends PowerCalculator {
-
     public static final String TAG = "MemoryPowerCalculator";
-    private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
-    private final double[] powerAverages;
+    private final UsageBasedPowerEstimator[] mPowerEstimators;
 
     public MemoryPowerCalculator(PowerProfile profile) {
         int numBuckets = profile.getNumElements(PowerProfile.POWER_MEMORY);
-        powerAverages = new double[numBuckets];
+        mPowerEstimators = new UsageBasedPowerEstimator[numBuckets];
         for (int i = 0; i < numBuckets; i++) {
-            powerAverages[i] = profile.getAveragePower(PowerProfile.POWER_MEMORY, i);
-            if (powerAverages[i] == 0 && DEBUG) {
-                Log.d(TAG, "Problem with PowerProfile. Received 0 value in MemoryPowerCalculator");
-            }
+            mPowerEstimators[i] = new UsageBasedPowerEstimator(
+                    profile.getAveragePower(PowerProfile.POWER_MEMORY, i));
         }
     }
 
     @Override
+    public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
+            long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query,
+            SparseArray<UserHandle> asUsers) {
+        final long durationMs = calculateDuration(batteryStats, rawRealtimeUs,
+                BatteryStats.STATS_SINCE_CHARGED);
+        final double powerMah = calculatePower(batteryStats, rawRealtimeUs,
+                BatteryStats.STATS_SINCE_CHARGED);
+        builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_MEMORY)
+                .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE, durationMs)
+                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, powerMah);
+    }
+
+    @Override
     public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
             long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
+        final long durationMs = calculateDuration(batteryStats, rawRealtimeUs, statsType);
+        final double powerMah = calculatePower(batteryStats, rawRealtimeUs, statsType);
         BatterySipper memory = new BatterySipper(BatterySipper.DrainType.MEMORY, null, 0);
-        calculateRemaining(memory, batteryStats, rawRealtimeUs, rawUptimeUs, statsType);
+        memory.usageTimeMs = durationMs;
+        memory.usagePowerMah = powerMah;
         memory.sumPower();
         if (memory.totalPowerMah > 0) {
             sippers.add(memory);
         }
     }
 
-    private void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
-            long rawUptimeUs, int statsType) {
-        double totalMah = 0;
-        long totalTimeMs = 0;
-        LongSparseArray<? extends BatteryStats.Timer> timers = stats.getKernelMemoryStats();
-        for (int i = 0; i < timers.size() && i < powerAverages.length; i++) {
-            double mAatRail = powerAverages[(int) timers.keyAt(i)];
-            long timeMs = timers.valueAt(i).getTotalTimeLocked(rawRealtimeUs, statsType);
-            double mAm = (mAatRail * timeMs) / (1000*60);
-            if(DEBUG) {
-                Log.d(TAG, "Calculating mAh for bucket " + timers.keyAt(i) + " while unplugged");
-                Log.d(TAG, "Converted power profile number from "
-                        + powerAverages[(int) timers.keyAt(i)] + " into " + mAatRail);
-                Log.d(TAG, "Calculated mAm " + mAm);
-            }
-            totalMah += mAm/60;
-            totalTimeMs += timeMs;
+    private long calculateDuration(BatteryStats batteryStats, long rawRealtimeUs, int statsType) {
+        long usageDurationMs = 0;
+        LongSparseArray<? extends BatteryStats.Timer> timers = batteryStats.getKernelMemoryStats();
+        for (int i = 0; i < timers.size() && i < mPowerEstimators.length; i++) {
+            usageDurationMs += mPowerEstimators[i].calculateDuration(timers.valueAt(i),
+                    rawRealtimeUs, statsType);
         }
-        app.usagePowerMah = totalMah;
-        app.usageTimeMs = totalTimeMs;
-        if (DEBUG) {
-            Log.d(TAG, String.format("Calculated total mAh for memory %f while unplugged %d ",
-                    totalMah, totalTimeMs));
+        return usageDurationMs;
+    }
+
+    private double calculatePower(BatteryStats batteryStats, long rawRealtimeUs, int statsType) {
+        double powerMah = 0;
+        LongSparseArray<? extends BatteryStats.Timer> timers = batteryStats.getKernelMemoryStats();
+        for (int i = 0; i < timers.size() && i < mPowerEstimators.length; i++) {
+            UsageBasedPowerEstimator estimator = mPowerEstimators[(int) timers.keyAt(i)];
+            final long usageDurationMs =
+                    estimator.calculateDuration(timers.valueAt(i), rawRealtimeUs, statsType);
+            powerMah += estimator.calculatePower(usageDurationMs);
         }
+        return powerMah;
     }
 }
diff --git a/core/java/com/android/internal/os/OWNERS b/core/java/com/android/internal/os/OWNERS
index 8f78b2a..1b07aa0 100644
--- a/core/java/com/android/internal/os/OWNERS
+++ b/core/java/com/android/internal/os/OWNERS
@@ -6,3 +6,5 @@
 per-file BatteryStats* = file:/BATTERY_STATS_OWNERS
 per-file BatteryUsageStats* = file:/BATTERY_STATS_OWNERS
 per-file *PowerCalculator* = file:/BATTERY_STATS_OWNERS
+per-file *PowerEstimator* = file:/BATTERY_STATS_OWNERS
+
diff --git a/core/java/com/android/internal/os/PhonePowerCalculator.java b/core/java/com/android/internal/os/PhonePowerCalculator.java
index 992c487..6ab8c90 100644
--- a/core/java/com/android/internal/os/PhonePowerCalculator.java
+++ b/core/java/com/android/internal/os/PhonePowerCalculator.java
@@ -30,20 +30,20 @@
  * Estimates power consumed by telephony.
  */
 public class PhonePowerCalculator extends PowerCalculator {
-    private final PowerProfile mPowerProfile;
+    private final UsageBasedPowerEstimator mPowerEstimator;
 
     public PhonePowerCalculator(PowerProfile powerProfile) {
-        mPowerProfile = powerProfile;
+        mPowerEstimator = new UsageBasedPowerEstimator(
+                powerProfile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE));
     }
 
     @Override
     public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
             long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query,
             SparseArray<UserHandle> asUsers) {
-        long phoneOnTimeMs = batteryStats.getPhoneOnTime(rawRealtimeUs,
+        final long phoneOnTimeMs = batteryStats.getPhoneOnTime(rawRealtimeUs,
                 BatteryStats.STATS_SINCE_CHARGED) / 1000;
-        double phoneOnPower = mPowerProfile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE)
-                * phoneOnTimeMs / (60 * 60 * 1000);
+        final double phoneOnPower = mPowerEstimator.calculatePower(phoneOnTimeMs);
         if (phoneOnPower != 0) {
             builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_PHONE)
                     .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, phoneOnPower)
@@ -54,9 +54,8 @@
     @Override
     public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
             long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
-        long phoneOnTimeMs = batteryStats.getPhoneOnTime(rawRealtimeUs, statsType) / 1000;
-        double phoneOnPower = mPowerProfile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE)
-                * phoneOnTimeMs / (60 * 60 * 1000);
+        final long phoneOnTimeMs = batteryStats.getPhoneOnTime(rawRealtimeUs, statsType) / 1000;
+        final double phoneOnPower = mPowerEstimator.calculatePower(phoneOnTimeMs);
         if (phoneOnPower != 0) {
             BatterySipper bs = new BatterySipper(BatterySipper.DrainType.PHONE, null, 0);
             bs.usagePowerMah = phoneOnPower;
diff --git a/core/java/com/android/internal/os/ScreenPowerCalculator.java b/core/java/com/android/internal/os/ScreenPowerCalculator.java
index 09fb75b..25f6b4d 100644
--- a/core/java/com/android/internal/os/ScreenPowerCalculator.java
+++ b/core/java/com/android/internal/os/ScreenPowerCalculator.java
@@ -16,7 +16,11 @@
 
 package com.android.internal.os;
 
+import android.os.BatteryConsumer;
 import android.os.BatteryStats;
+import android.os.BatteryUsageStats;
+import android.os.BatteryUsageStatsQuery;
+import android.os.SystemBatteryConsumer;
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.SparseArray;
@@ -30,10 +34,29 @@
     private static final String TAG = "ScreenPowerCalculator";
     private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
 
-    private final PowerProfile mPowerProfile;
+    private final UsageBasedPowerEstimator mScreenOnPowerEstimator;
+    private final UsageBasedPowerEstimator mScreenFullPowerEstimator;
 
     public ScreenPowerCalculator(PowerProfile powerProfile) {
-        mPowerProfile = powerProfile;
+        mScreenOnPowerEstimator = new UsageBasedPowerEstimator(
+                powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_ON));
+        mScreenFullPowerEstimator = new UsageBasedPowerEstimator(
+                powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL));
+    }
+
+    @Override
+    public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
+            long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query,
+            SparseArray<UserHandle> asUsers) {
+        final long durationMs = computeDuration(batteryStats, rawRealtimeUs,
+                BatteryStats.STATS_SINCE_CHARGED);
+        final double powerMah = computePower(batteryStats, rawRealtimeUs,
+                BatteryStats.STATS_SINCE_CHARGED, durationMs);
+        if (powerMah != 0) {
+            builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_SCREEN)
+                    .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE, durationMs)
+                    .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, powerMah);
+        }
     }
 
     /**
@@ -42,30 +65,35 @@
     @Override
     public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
             long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
-        double power = 0;
-        final long screenOnTimeMs = batteryStats.getScreenOnTime(rawRealtimeUs, statsType) / 1000;
-        power += screenOnTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_SCREEN_ON);
-        final double screenFullPower =
-                mPowerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL);
-        for (int i = 0; i < BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; i++) {
-            final double screenBinPower = screenFullPower * (i + 0.5f)
-                    / BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS;
-            final long brightnessTime =
-                    batteryStats.getScreenBrightnessTime(i, rawRealtimeUs, statsType) / 1000;
-            final double p = screenBinPower * brightnessTime;
-            if (DEBUG && p != 0) {
-                Log.d(TAG, "Screen bin #" + i + ": time=" + brightnessTime
-                        + " power=" + formatCharge(p / (60 * 60 * 1000)));
-            }
-            power += p;
-        }
-        power /= (60 * 60 * 1000); // To hours
-        if (power != 0) {
+        final long durationMs = computeDuration(batteryStats, rawRealtimeUs, statsType);
+        final double powerMah = computePower(batteryStats, rawRealtimeUs, statsType, durationMs);
+        if (powerMah != 0) {
             final BatterySipper bs = new BatterySipper(BatterySipper.DrainType.SCREEN, null, 0);
-            bs.usagePowerMah = power;
-            bs.usageTimeMs = screenOnTimeMs;
+            bs.usagePowerMah = powerMah;
+            bs.usageTimeMs = durationMs;
             bs.sumPower();
             sippers.add(bs);
         }
     }
+
+    private long computeDuration(BatteryStats batteryStats, long rawRealtimeUs, int statsType) {
+        return batteryStats.getScreenOnTime(rawRealtimeUs, statsType) / 1000;
+    }
+
+    private double computePower(BatteryStats batteryStats, long rawRealtimeUs, int statsType,
+            long durationMs) {
+        double power = mScreenOnPowerEstimator.calculatePower(durationMs);
+        for (int i = 0; i < BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; i++) {
+            final long brightnessTime =
+                    batteryStats.getScreenBrightnessTime(i, rawRealtimeUs, statsType) / 1000;
+            final double binPowerMah = mScreenFullPowerEstimator.calculatePower(brightnessTime)
+                    * (i + 0.5f) / BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS;
+            if (DEBUG && binPowerMah != 0) {
+                Log.d(TAG, "Screen bin #" + i + ": time=" + brightnessTime
+                        + " power=" + formatCharge(binPowerMah));
+            }
+            power += binPowerMah;
+        }
+        return power;
+    }
 }
diff --git a/core/java/com/android/internal/os/SystemServicePowerCalculator.java b/core/java/com/android/internal/os/SystemServicePowerCalculator.java
index b15dff6..55fc1bb 100644
--- a/core/java/com/android/internal/os/SystemServicePowerCalculator.java
+++ b/core/java/com/android/internal/os/SystemServicePowerCalculator.java
@@ -16,7 +16,11 @@
 
 package com.android.internal.os;
 
+import android.os.BatteryConsumer;
 import android.os.BatteryStats;
+import android.os.BatteryUsageStats;
+import android.os.BatteryUsageStatsQuery;
+import android.os.UidBatteryConsumer;
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.SparseArray;
@@ -46,28 +50,35 @@
     }
 
     @Override
+    public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
+            long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query,
+            SparseArray<UserHandle> asUsers) {
+        calculateSystemServicePower(batteryStats);
+        super.calculate(builder, batteryStats, rawRealtimeUs, rawUptimeUs, query, asUsers);
+    }
+
+    @Override
+    protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
+            long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
+        app.setConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES,
+                calculateSystemServerCpuPowerMah(u));
+    }
+
+    @Override
     public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
             long rawRealtimeUs, long rawUptimeUs, int statsType,
             SparseArray<UserHandle> asUsers) {
-        updateSystemServicePower(batteryStats);
+        calculateSystemServicePower(batteryStats);
         super.calculate(sippers, batteryStats, rawRealtimeUs, rawUptimeUs, statsType, asUsers);
     }
 
     @Override
     protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
             long rawUptimeUs, int statsType) {
-        final double proportionalUsage = u.getProportionalSystemServiceUsage();
-        if (proportionalUsage > 0 && mSystemServicePowerMaUs != null) {
-            double cpuPowerMaUs = 0;
-            for (int i = 0; i < mSystemServicePowerMaUs.length; i++) {
-                cpuPowerMaUs += mSystemServicePowerMaUs[i] * proportionalUsage;
-            }
-
-            app.systemServiceCpuPowerMah = cpuPowerMaUs / MICROSEC_IN_HR;
-        }
+        app.systemServiceCpuPowerMah = calculateSystemServerCpuPowerMah(u);
     }
 
-    private void updateSystemServicePower(BatteryStats batteryStats) {
+    private void calculateSystemServicePower(BatteryStats batteryStats) {
         final long[] systemServiceTimeAtCpuSpeeds = batteryStats.getSystemServiceTimeAtCpuSpeeds();
         if (systemServiceTimeAtCpuSpeeds == null) {
             return;
@@ -94,6 +105,17 @@
         }
     }
 
+    private double calculateSystemServerCpuPowerMah(BatteryStats.Uid u) {
+        double cpuPowerMaUs = 0;
+        final double proportionalUsage = u.getProportionalSystemServiceUsage();
+        if (proportionalUsage > 0 && mSystemServicePowerMaUs != null) {
+            for (int i = 0; i < mSystemServicePowerMaUs.length; i++) {
+                cpuPowerMaUs += mSystemServicePowerMaUs[i] * proportionalUsage;
+            }
+        }
+        return cpuPowerMaUs / MICROSEC_IN_HR;
+    }
+
     @Override
     public void reset() {
         mSystemServicePowerMaUs = null;
diff --git a/core/java/com/android/internal/os/UsageBasedPowerEstimator.java b/core/java/com/android/internal/os/UsageBasedPowerEstimator.java
new file mode 100644
index 0000000..5910b61
--- /dev/null
+++ b/core/java/com/android/internal/os/UsageBasedPowerEstimator.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import android.os.BatteryStats;
+
+/**
+ * Implements a simple linear power model based on the assumption that the power consumer
+ * consumes a fixed current when it is used and no current when it is unused.
+ *
+ * <code>power = usageDuration * averagePower</code>
+ */
+public class UsageBasedPowerEstimator {
+    private static final double MILLIS_IN_HOUR = 1000.0 * 60 * 60;
+    private final double mAveragePowerMahPerMs;
+
+    public UsageBasedPowerEstimator(double averagePowerMilliAmp) {
+        mAveragePowerMahPerMs = averagePowerMilliAmp / MILLIS_IN_HOUR;
+    }
+
+    /**
+     * Given a {@link BatteryStats.Timer}, returns the accumulated duration.
+     */
+    public long calculateDuration(BatteryStats.Timer timer, long rawRealtimeUs, int statsType) {
+        return timer == null ? 0 : timer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000;
+    }
+
+    /**
+     * Given a duration in milliseconds, return the estimated power consumption.
+     */
+    public double calculatePower(long durationMs) {
+        return mAveragePowerMahPerMs * durationMs;
+    }
+}
diff --git a/core/java/com/android/internal/os/VideoPowerCalculator.java b/core/java/com/android/internal/os/VideoPowerCalculator.java
new file mode 100644
index 0000000..5d6caf5
--- /dev/null
+++ b/core/java/com/android/internal/os/VideoPowerCalculator.java
@@ -0,0 +1,45 @@
+/*
+ * 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.internal.os;
+
+import android.os.BatteryConsumer;
+import android.os.BatteryStats;
+import android.os.BatteryUsageStatsQuery;
+import android.os.UidBatteryConsumer;
+
+/**
+ * A {@link PowerCalculator} to calculate power consumed by video hardware.
+ *
+ * Also see {@link PowerProfile#POWER_VIDEO}.
+ */
+public class VideoPowerCalculator extends PowerCalculator {
+    private final UsageBasedPowerEstimator mPowerEstimator;
+
+    public VideoPowerCalculator(PowerProfile powerProfile) {
+        mPowerEstimator = new UsageBasedPowerEstimator(
+                powerProfile.getAveragePower(PowerProfile.POWER_VIDEO));
+    }
+
+    @Override
+    protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
+            long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
+        final long durationMs = mPowerEstimator.calculateDuration(u.getVideoTurnedOnTimer(),
+                rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED);
+        final double powerMah = mPowerEstimator.calculatePower(durationMs);
+        app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_VIDEO, durationMs)
+                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_VIDEO, powerMah);
+    }
+}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 8c9da66..94ef64f 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -347,12 +347,6 @@
         },
     },
 
-    product_variables: {
-        experimental_mte: {
-            cflags: ["-DANDROID_EXPERIMENTAL_MTE"],
-        },
-    },
-
     // Workaround Clang LTO crash.
     lto: {
         never: true,
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index efede21..3156f71 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -843,7 +843,7 @@
   PrepareDir(user_source, 0710, user_id ? AID_ROOT : AID_SHELL,
              multiuser_get_uid(user_id, AID_EVERYBODY), fail_fn);
 
-  bool isAppDataIsolationEnabled = GetBoolProperty(kVoldAppDataIsolation, true);
+  bool isAppDataIsolationEnabled = GetBoolProperty(kVoldAppDataIsolation, false);
 
   if (mount_mode == MOUNT_EXTERNAL_PASS_THROUGH) {
       const std::string pass_through_source = StringPrintf("/mnt/pass_through/%d", user_id);
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 8de30f8..944edb0 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -521,6 +521,11 @@
         (section).args = "power_stats --proto model"
     ];
 
+    optional com.android.server.powerstats.PowerStatsServiceResidencyProto powerstats_residency = 3056 [
+        (section).type = SECTION_DUMPSYS,
+        (section).args = "power_stats --proto residency"
+    ];
+
     // Dumps in text format (on userdebug and eng builds only): 4000 ~ 4999
     optional android.util.TextDumpProto textdump_wifi = 4000 [
         (section).type = SECTION_TEXT_DUMPSYS,
diff --git a/core/proto/android/server/powerstatsservice.proto b/core/proto/android/server/powerstatsservice.proto
index 9a7ed7c..30c4274 100644
--- a/core/proto/android/server/powerstatsservice.proto
+++ b/core/proto/android/server/powerstatsservice.proto
@@ -41,6 +41,16 @@
 }
 
 /**
+ * IncidentReportResidencyProto is used only in the parsing tool located
+ * in frameworks/base/tools which is used to parse this data out of
+ * incident reports.
+ */
+message IncidentReportResidencyProto {
+    /** Section number matches that in incident.proto */
+    optional PowerStatsServiceResidencyProto incident_report = 3056;
+}
+
+/**
  * EnergyConsumer (model) data is exposed by the PowerStats HAL.  This data
  * represents modeled energy consumption estimates and is provided per
  * subsystem.  The default subsystems are defined in EnergyConsumerId.aidl.
@@ -63,6 +73,99 @@
 }
 
 /**
+ * A PowerEntity is defined as a platform subsystem, peripheral, or power domain
+ * that impacts the total device power consumption.  PowerEntityInfo is
+ * information related to each power entity.  Each PowerEntity may reside in one
+ * of multiple states. It may also transition from one state to another.
+ * StateResidency is defined as an accumulation of time that a PowerEntity
+ * resided in each of its possible states, the number of times that each state
+ * was entered, and a timestamp corresponding to the last time that state was
+ * entered.
+ */
+message PowerStatsServiceResidencyProto {
+    repeated PowerEntityInfoProto power_entity_info = 1;
+    repeated StateResidencyResultProto state_residency_result = 2;
+}
+
+/**
+ * Information about the possible states for a particular PowerEntity.
+ */
+message StateInfoProto {
+    /**
+     * Unique (for a given PowerEntityInfo) ID of this StateInfo
+     */
+    optional int32 state_id = 1;
+    /**
+     * Unique (for a given PowerEntityInfo) name of the state. Vendor/device specific.
+     * Opaque to framework
+     */
+    optional string state_name = 2;
+}
+
+/**
+ * A PowerEntity is defined as a platform subsystem, peripheral, or power domain
+ * that impacts the total device power consumption.  PowerEntityInfo is
+ * information about a PowerEntity.  It includes an array of information about
+ * each possible state of the PowerEntity.
+ */
+message PowerEntityInfoProto {
+    /**
+     * Unique ID of this PowerEntityInfo
+     */
+    optional int32 power_entity_id = 1;
+    /**
+     * Unique name of the PowerEntity. Vendor/device specific. Opaque to framework
+     */
+    optional string power_entity_name = 2;
+    /**
+     * List of states that the PowerEntity may reside in
+     */
+    repeated StateInfoProto states = 3;
+}
+
+/**
+ * StateResidency is defined as an accumulation of time that a PowerEntity
+ * resided in each of its possible states, the number of times that each state
+ * was entered, and a timestamp corresponding to the last time that state was
+ * entered.  Data is accumulated starting at device boot.
+ */
+message StateResidencyProto {
+    /**
+     * ID of the state associated with this residency
+     */
+    optional int32 state_id = 1;
+    /**
+     * Total time in milliseconds that the corresponding PowerEntity resided
+     * in this state since boot
+     */
+    optional int64 total_time_in_state_ms = 2;
+    /**
+     * Total number of times that the state was entered since boot
+     */
+    optional int64 total_state_entry_count = 3;
+    /**
+     * Last time this state was entered. Time in milliseconds since boot
+     */
+    optional int64 last_entry_timestamp_ms = 4;
+}
+
+/**
+ * A StateResidencyResult is an array of StateResidencies for a particular
+ * PowerEntity.  The StateResidencyResult can be matched to its corresponding
+ * PowerEntityInfo through the power_entity_id field.
+ */
+message StateResidencyResultProto {
+    /**
+     * ID of the PowerEntity associated with this result
+     */
+    optional int32 power_entity_id = 1;
+    /**
+     * Residency for each state in the PowerEntity's state space
+     */
+    repeated StateResidencyProto state_residency_data = 2;
+}
+
+/**
  * Energy consumer ID:
  * A list of default subsystems for which energy consumption estimates
  * may be provided (hardware dependent).
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 8682fea..ce3ed9d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2676,11 +2676,11 @@
          The app can check whether it has this authorization by calling
          {@link android.provider.Settings#canDrawOverlays
          Settings.canDrawOverlays()}.
-         <p>Protection level: signature|preinstalled|appop|pre23|development -->
+         <p>Protection level: signature|appop|installer|pre23|development -->
     <permission android:name="android.permission.SYSTEM_ALERT_WINDOW"
         android:label="@string/permlab_systemAlertWindow"
         android:description="@string/permdesc_systemAlertWindow"
-        android:protectionLevel="signature|preinstalled|appop|pre23|development" />
+        android:protectionLevel="signature|appop|installer|pre23|development" />
 
     <!-- @deprecated Use {@link android.Manifest.permission#REQUEST_COMPANION_RUN_IN_BACKGROUND}
          @hide
@@ -3591,6 +3591,14 @@
     <permission android:name="android.permission.BIND_CONTENT_CAPTURE_SERVICE"
                 android:protectionLevel="signature" />
 
+    <!-- Must be required by a android.service.translation.TranslationService,
+         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).
+         <p>Protection level: signature
+     -->
+    <permission android:name="android.permission.BIND_TRANSLATION_SERVICE"
+                android:protectionLevel="signature" />
+
     <!-- 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).
@@ -5317,6 +5325,12 @@
     <permission android:name="android.permission.BIND_IMPRESSION_ATTESTATION_SERVICE"
         android:protectionLevel="signature" />
 
+    <!-- @hide @TestApi Allows an application to enable/disable toast rate limiting.
+         <p>Not for use by third-party applications.
+    -->
+    <permission android:name="android.permission.MANAGE_TOAST_RATE_LIMITING"
+                android:protectionLevel="signature" />
+
     <!-- Attribution for Geofencing service. -->
     <attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/>
     <!-- Attribution for Country Detector. -->
diff --git a/core/res/res/layout/notification_template_material_base.xml b/core/res/res/layout/notification_template_material_base.xml
index 0006384..41be36b 100644
--- a/core/res/res/layout/notification_template_material_base.xml
+++ b/core/res/res/layout/notification_template_material_base.xml
@@ -45,6 +45,45 @@
         android:padding="@dimen/notification_icon_circle_padding"
         />
 
+    <ImageView
+        android:id="@+id/right_icon"
+        android:layout_width="@dimen/notification_right_icon_size"
+        android:layout_height="@dimen/notification_right_icon_size"
+        android:layout_gravity="center_vertical|end"
+        android:layout_marginTop="@dimen/notification_right_icon_headerless_margin"
+        android:layout_marginBottom="@dimen/notification_right_icon_headerless_margin"
+        android:layout_marginEnd="@dimen/notification_header_expand_icon_size"
+        android:background="@drawable/notification_large_icon_outline"
+        android:importantForAccessibility="no"
+        android:scaleType="centerCrop"
+        />
+
+    <FrameLayout
+        android:id="@+id/alternate_expand_target"
+        android:layout_width="@dimen/notification_content_margin_start"
+        android:layout_height="match_parent"
+        android:layout_gravity="start"
+        android:importantForAccessibility="no"
+        />
+
+    <FrameLayout
+        android:id="@+id/expand_button_touch_container"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_gravity="end">
+
+        <com.android.internal.widget.NotificationExpandButton
+            android:id="@+id/expand_button"
+            android:layout_width="@dimen/notification_header_expand_icon_size"
+            android:layout_height="@dimen/notification_header_expand_icon_size"
+            android:layout_gravity="center_vertical|end"
+            android:contentDescription="@string/expand_button_content_description_collapsed"
+            android:paddingTop="@dimen/notification_expand_button_padding_top"
+            android:scaleType="center"
+            />
+
+    </FrameLayout>
+
     <LinearLayout
         android:id="@+id/notification_headerless_view_column"
         android:layout_width="match_parent"
@@ -64,6 +103,7 @@
         variant is 56dp and the 2- and 3-line variants are both 76dp.
         -->
         <FrameLayout
+            android:id="@+id/notification_headerless_margin_extra_top"
             android:layout_width="match_parent"
             android:layout_height="@dimen/notification_headerless_margin_extra"
             android:layout_weight="1"
@@ -135,6 +175,7 @@
         variant is 56dp and the 2- and 3-line variants are both 76dp.
         -->
         <FrameLayout
+            android:id="@+id/notification_headerless_margin_extra_bottom"
             android:layout_width="match_parent"
             android:layout_height="@dimen/notification_headerless_margin_extra"
             android:layout_weight="1"
@@ -142,43 +183,4 @@
 
     </LinearLayout>
 
-    <ImageView
-        android:id="@+id/right_icon"
-        android:layout_width="@dimen/notification_right_icon_size"
-        android:layout_height="@dimen/notification_right_icon_size"
-        android:layout_gravity="center_vertical|end"
-        android:layout_marginTop="@dimen/notification_right_icon_headerless_margin"
-        android:layout_marginBottom="@dimen/notification_right_icon_headerless_margin"
-        android:layout_marginEnd="@dimen/notification_header_expand_icon_size"
-        android:background="@drawable/notification_large_icon_outline"
-        android:importantForAccessibility="no"
-        android:scaleType="centerCrop"
-        />
-
-    <FrameLayout
-        android:id="@+id/alternate_expand_target"
-        android:layout_width="@dimen/notification_content_margin_start"
-        android:layout_height="match_parent"
-        android:layout_gravity="start"
-        android:importantForAccessibility="no"
-        />
-
-    <FrameLayout
-        android:id="@+id/expand_button_touch_container"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:layout_gravity="end">
-
-        <com.android.internal.widget.NotificationExpandButton
-            android:id="@+id/expand_button"
-            android:layout_width="@dimen/notification_header_expand_icon_size"
-            android:layout_height="@dimen/notification_header_expand_icon_size"
-            android:layout_gravity="center_vertical|end"
-            android:contentDescription="@string/expand_button_content_description_collapsed"
-            android:paddingTop="@dimen/notification_expand_button_padding_top"
-            android:scaleType="center"
-            />
-
-    </FrameLayout>
-
 </com.android.internal.widget.NotificationMaxHeightFrameLayout>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 0721f8e..3adb318 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -100,7 +100,7 @@
     <string name="peerTtyModeHco" msgid="5626377160840915617">"নেটৱৰ্ক পীয়েৰে TTY ম\'ড HCOলৈ সলনি কৰিবলৈ অনুৰোধ কৰিছে"</string>
     <string name="peerTtyModeVco" msgid="572208600818270944">"নেটৱৰ্ক পীয়েৰে TTY ম\'ড VCO লৈ সলনি কৰিবলৈ অনুৰোধ কৰিছে"</string>
     <string name="peerTtyModeOff" msgid="2420380956369226583">"নেটৱৰ্ক পীয়েৰে TTY ম\'ড OFFলৈ সলনি কৰিবলৈ অনুৰোধ কৰিছে"</string>
-    <string name="serviceClassVoice" msgid="2065556932043454987">"কণ্ঠস্বৰ"</string>
+    <string name="serviceClassVoice" msgid="2065556932043454987">"Voice"</string>
     <string name="serviceClassData" msgid="4148080018967300248">"ডেটা"</string>
     <string name="serviceClassFAX" msgid="2561653371698904118">"ফেক্স"</string>
     <string name="serviceClassSMS" msgid="1547664561704509004">"এছএমএছ"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 967bb92..016e77b 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1319,7 +1319,7 @@
     <string name="usb_power_notification_message" msgid="7284765627437897702">"કનેક્ટ કરેલ ઉપકરણ ચાર્જ થઈ રહ્યું છે. વધુ વિકલ્પો માટે ટૅપ કરો."</string>
     <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"એનાલોગ ઑડિઓ ઍક્સેસરી મળી"</string>
     <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"જોડેલ ઉપકરણ આ ફોન સાથે સુસંગત નથી. વધુ જાણવા માટે ટૅપ કરો."</string>
-    <string name="adb_active_notification_title" msgid="408390247354560331">"USB ડીબગિંગ કનેક્ટ થયું."</string>
+    <string name="adb_active_notification_title" msgid="408390247354560331">"USB ડિબગીંગ કનેક્ટ થયું."</string>
     <string name="adb_active_notification_message" msgid="5617264033476778211">"USB ડિબગીંગ બંધ કરવા માટે ટૅપ કરો"</string>
     <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB ડિબગીંગને અક્ષમ કરવા માટે પસંદ કરો."</string>
     <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"વાયરલેસ ડિબગીંગ કનેક્ટ કરો"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 0df69d9..a8afbbe 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -100,7 +100,7 @@
     <string name="peerTtyModeHco" msgid="5626377160840915617">"पीयर ने टेलीटाइपराइटर (TTY) मोड एचसीओ (HCO) का अनुरोध किया"</string>
     <string name="peerTtyModeVco" msgid="572208600818270944">"पीयर ने टेलीटाइपराइटर (TTY) मोड वीसीओ (VCO) का अनुरोध किया"</string>
     <string name="peerTtyModeOff" msgid="2420380956369226583">"पीयर ने टेलीटाइपराइटर (TTY) मोड बंद का अनुरोध किया"</string>
-    <string name="serviceClassVoice" msgid="2065556932043454987">"आवाज़"</string>
+    <string name="serviceClassVoice" msgid="2065556932043454987">"Voice"</string>
     <string name="serviceClassData" msgid="4148080018967300248">"डेटा"</string>
     <string name="serviceClassFAX" msgid="2561653371698904118">"फ़ैक्स"</string>
     <string name="serviceClassSMS" msgid="1547664561704509004">"मैसेज (एसएमएस)"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 937645e..b7356e1 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -100,7 +100,7 @@
     <string name="peerTtyModeHco" msgid="5626377160840915617">"ಪೀರ್ ವಿನಂತಿಸಿಕೊಂಡ TTY ಮೋಡ್ HCO"</string>
     <string name="peerTtyModeVco" msgid="572208600818270944">"ಪೀರ್ ವಿನಂತಿಸಿಕೊಂಡ TTY ಮೋಡ್ VCO"</string>
     <string name="peerTtyModeOff" msgid="2420380956369226583">"ಪೀರ್ ವಿನಂತಿಸಿಕೊಂಡ TTY ಮೋಡ್ ಆಫ್ ಆಗಿದೆ"</string>
-    <string name="serviceClassVoice" msgid="2065556932043454987">"ಧ್ವನಿ"</string>
+    <string name="serviceClassVoice" msgid="2065556932043454987">"Voice"</string>
     <string name="serviceClassData" msgid="4148080018967300248">"ಡೇಟಾ"</string>
     <string name="serviceClassFAX" msgid="2561653371698904118">"ಫ್ಯಾಕ್ಸ್"</string>
     <string name="serviceClassSMS" msgid="1547664561704509004">"SMS"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index e7a1628..30c0d03 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -100,7 +100,7 @@
     <string name="peerTtyModeHco" msgid="5626377160840915617">"പിയർ അഭ്യർത്ഥിച്ച TTY മോഡ് HCO"</string>
     <string name="peerTtyModeVco" msgid="572208600818270944">"പിയർ അഭ്യർത്ഥിച്ച TTY മോഡ് VCO"</string>
     <string name="peerTtyModeOff" msgid="2420380956369226583">"പിയർ അഭ്യർത്ഥിച്ച TTY മോഡ് \'ഓഫ്\'"</string>
-    <string name="serviceClassVoice" msgid="2065556932043454987">"ശബ്‌ദം"</string>
+    <string name="serviceClassVoice" msgid="2065556932043454987">"Voice"</string>
     <string name="serviceClassData" msgid="4148080018967300248">"ഡാറ്റ"</string>
     <string name="serviceClassFAX" msgid="2561653371698904118">"ഫാക്സ്"</string>
     <string name="serviceClassSMS" msgid="1547664561704509004">"SMS"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index b5935e9..2124d49 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -100,7 +100,7 @@
     <string name="peerTtyModeHco" msgid="5626377160840915617">"ପୀଅର୍‌ ଅନୁରୋଧ କରିଥିବା TTY ମୋଡ୍‍ HCO ଅଟେ"</string>
     <string name="peerTtyModeVco" msgid="572208600818270944">"ପୀଅର୍‌ ଅନୁରୋଧ କରିଥିବା TTY ମୋଡ୍‍ VCO ଅଟେ"</string>
     <string name="peerTtyModeOff" msgid="2420380956369226583">"ପୀଅର୍‌ ଅନୁରୋଧ କରିଥିବା TTY ମୋଡ୍‍ OFF ଅଛି"</string>
-    <string name="serviceClassVoice" msgid="2065556932043454987">"ଭଏସ୍"</string>
+    <string name="serviceClassVoice" msgid="2065556932043454987">"Voice"</string>
     <string name="serviceClassData" msgid="4148080018967300248">"ଡାଟା"</string>
     <string name="serviceClassFAX" msgid="2561653371698904118">"ଫାକ୍ସ"</string>
     <string name="serviceClassSMS" msgid="1547664561704509004">"SMS"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 8d5e974..4518a3b 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1319,7 +1319,7 @@
     <string name="usb_power_notification_message" msgid="7284765627437897702">"ਕਨੈਕਟ ਕੀਤਾ ਡੀਵਾਈਸ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ। ਹੋਰ ਵਿਕਲਪਾਂ ਲਈ ਟੈਪ ਕਰੋ।"</string>
     <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"ਐਨਾਲੌਗ  ਆਡੀਓ  ਉਪਸਾਧਨ ਦਾ ਪਤਾ ਲੱਗਿਆ"</string>
     <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"ਨੱਥੀ ਕੀਤਾ ਡੀਵਾਈਸ ਇਸ ਫ਼ੋਨ ਦੇ ਅਨੁਰੂਪ ਨਹੀਂ ਹੈ। ਹੋਰ ਜਾਣਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
-    <string name="adb_active_notification_title" msgid="408390247354560331">"USB ਡੀਬਗਿੰਗ ਕਨੈਕਟ ਕੀਤੀ"</string>
+    <string name="adb_active_notification_title" msgid="408390247354560331">"USB ਡੀਬੱਗਿੰਗ ਕਨੈਕਟ ਕੀਤੀ"</string>
     <string name="adb_active_notification_message" msgid="5617264033476778211">"USB ਡੀਬੱਗਿੰਗ ਬੰਦ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
     <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB ਡੀਬੱਗਿੰਗ ਅਯੋਗ ਬਣਾਉਣ ਲਈ ਚੁਣੋ।"</string>
     <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ਵਾਇਰਲੈੱਸ ਡੀਬੱਗਿੰਗ ਨੂੰ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 0f5d000..6483db1 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -100,7 +100,7 @@
     <string name="peerTtyModeHco" msgid="5626377160840915617">"అవతలి వారు HCO TTY మోడ్‌ని అభ్యర్థించారు"</string>
     <string name="peerTtyModeVco" msgid="572208600818270944">"అవతలి వారు VCO TTY మోడ్‌ని అభ్యర్థించారు"</string>
     <string name="peerTtyModeOff" msgid="2420380956369226583">"అవతలి వారు OFF TTY మోడ్‌ని అభ్యర్థించారు"</string>
-    <string name="serviceClassVoice" msgid="2065556932043454987">"వాయిస్"</string>
+    <string name="serviceClassVoice" msgid="2065556932043454987">"Voice"</string>
     <string name="serviceClassData" msgid="4148080018967300248">"డేటా"</string>
     <string name="serviceClassFAX" msgid="2561653371698904118">"ఫ్యాక్స్"</string>
     <string name="serviceClassSMS" msgid="1547664561704509004">"SMS"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 7ca3faf..ef54db1a 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -8292,6 +8292,23 @@
     </declare-styleable>
 
     <!-- =============================== -->
+    <!-- Translation attributes -->
+    <!-- =============================== -->
+    <eat-comment />
+
+    <!-- Use <code>translation-service</code> as the root tag of the XML resource that describes
+         a {@link android.service.translation.TranslationService}, which is referenced from
+         its {@link android.service.translation.TranslationService#SERVICE_META_DATA} meta-data
+         entry.
+         @hide @SystemApi
+    -->
+    <declare-styleable name="TranslationService">
+        <!-- Fully qualified class name of an activity that allows the user to modify
+             the settings for this service. -->
+        <attr name="settingsActivity" />
+    </declare-styleable>
+
+    <!-- =============================== -->
     <!-- Contacts meta-data attributes -->
     <!-- =============================== -->
     <eat-comment />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index da658cc..cff1bda 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3724,6 +3724,14 @@
     -->
     <string name="config_defaultAugmentedAutofillService" translatable="false"></string>
 
+    <!-- The package name for the system's translation service.
+     This service must be trusted, as it can be activated without explicit consent of the user.
+     If no service with the specified name exists on the device, translation wil be
+     disabled.
+     Example: "com.android.translation/.TranslationService"
+-->
+    <string name="config_defaultTranslationService" translatable="false"></string>
+
     <!-- The package name for the system's app prediction service.
          This service must be trusted, as it can be activated without explicit consent of the user.
          Example: "com.android.intelligence/.AppPredictionService"
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index c326a40..3ae2131 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -305,12 +305,18 @@
     <!-- The top padding for the notification expand button. -->
     <dimen name="notification_expand_button_padding_top">1dp</dimen>
 
-    <!-- minimum vertical margin for the headerless notification content -->
+    <!-- minimum vertical margin for the headerless notification content, when cap = 60dp -->
     <dimen name="notification_headerless_margin_minimum">8dp</dimen>
 
-    <!-- extra vertical margin for the headerless notification content -->
+    <!-- extra vertical margin for the headerless notification content, when cap = 60dp -->
     <dimen name="notification_headerless_margin_extra">10dp</dimen>
 
+    <!-- minimum vertical margin for the headerless notification content, when cap = 48dp -->
+    <dimen name="notification_headerless_margin_constrained_minimum">14dp</dimen>
+
+    <!-- extra vertical margin for the headerless notification content, when cap = 48dp -->
+    <dimen name="notification_headerless_margin_constrained_extra">4dp</dimen>
+
     <!-- The height of each of the 1 or 2 lines in the headerless notification template -->
     <dimen name="notification_headerless_line_height">20sp</dimen>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 2df9684..5b42947 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2877,6 +2877,8 @@
   <java-symbol type="id" name="alternate_expand_target" />
   <java-symbol type="id" name="notification_header" />
   <java-symbol type="id" name="notification_top_line" />
+  <java-symbol type="id" name="notification_headerless_margin_extra_top" />
+  <java-symbol type="id" name="notification_headerless_margin_extra_bottom" />
   <java-symbol type="id" name="time_divider" />
   <java-symbol type="id" name="header_text_divider" />
   <java-symbol type="id" name="header_text_secondary_divider" />
@@ -2898,6 +2900,8 @@
   <java-symbol type="dimen" name="notification_header_icon_size" />
   <java-symbol type="dimen" name="notification_header_app_name_margin_start" />
   <java-symbol type="dimen" name="notification_header_separating_margin" />
+  <java-symbol type="dimen" name="notification_headerless_margin_constrained_minimum" />
+  <java-symbol type="dimen" name="notification_headerless_margin_constrained_extra" />
   <java-symbol type="string" name="default_notification_channel_label" />
   <java-symbol type="string" name="importance_from_user" />
   <java-symbol type="string" name="importance_from_person" />
@@ -3480,6 +3484,7 @@
   <java-symbol type="string" name="config_defaultWellbeingPackage" />
   <java-symbol type="string" name="config_defaultContentCaptureService" />
   <java-symbol type="string" name="config_defaultAugmentedAutofillService" />
+  <java-symbol type="string" name="config_defaultTranslationService" />
   <java-symbol type="string" name="config_defaultAppPredictionService" />
   <java-symbol type="string" name="config_defaultContentSuggestionsService" />
   <java-symbol type="string" name="config_defaultSearchUiService" />
diff --git a/core/tests/coretests/src/android/app/appsearch/external/app/SetSchemaRequestTest.java b/core/tests/coretests/src/android/app/appsearch/external/app/SetSchemaRequestTest.java
index 133efce..aab9229 100644
--- a/core/tests/coretests/src/android/app/appsearch/external/app/SetSchemaRequestTest.java
+++ b/core/tests/coretests/src/android/app/appsearch/external/app/SetSchemaRequestTest.java
@@ -16,6 +16,7 @@
 
 package android.app.appsearch;
 
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.testng.Assert.expectThrows;
diff --git a/core/tests/coretests/src/android/graphics/OWNERS b/core/tests/coretests/src/android/graphics/OWNERS
new file mode 100644
index 0000000..1e8478e
--- /dev/null
+++ b/core/tests/coretests/src/android/graphics/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 24939
+
+include /graphics/java/android/graphics/OWNERS
+
+per-file Font* = file:/graphics/java/android/graphics/fonts/OWNERS
+per-file Typeface* = file:/graphics/java/android/graphics/fonts/OWNERS
diff --git a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
index 82d066f..05ff218 100644
--- a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
+++ b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
@@ -67,6 +67,7 @@
     private static final String TEST_FONT_DIR;
     private static final String TEST_OEM_XML;
     private static final String TEST_OEM_DIR;
+    private static final String TEST_UPDATABLE_FONT_DIR;
 
     private static final float GLYPH_1EM_WIDTH;
     private static final float GLYPH_2EM_WIDTH;
@@ -82,9 +83,11 @@
         TEST_FONTS_XML = new File(cacheDir, "fonts.xml").getAbsolutePath();
         TEST_OEM_DIR = cacheDir.getAbsolutePath() + "/oem_fonts/";
         TEST_OEM_XML = new File(cacheDir, "fonts_customization.xml").getAbsolutePath();
+        TEST_UPDATABLE_FONT_DIR = cacheDir.getAbsolutePath() + "/updatable_fonts/";
 
         new File(TEST_FONT_DIR).mkdirs();
         new File(TEST_OEM_DIR).mkdirs();
+        new File(TEST_UPDATABLE_FONT_DIR).mkdirs();
 
         final AssetManager am =
                 InstrumentationRegistry.getInstrumentation().getContext().getAssets();
@@ -103,18 +106,11 @@
                 InstrumentationRegistry.getInstrumentation().getContext().getAssets();
         for (final String fontFile : TEST_FONT_FILES) {
             final String sourceInAsset = "fonts/" + fontFile;
-            final File outInCache = new File(TEST_FONT_DIR, fontFile);
-            try (InputStream is = am.open(sourceInAsset)) {
-                Files.copy(is, outInCache.toPath(), StandardCopyOption.REPLACE_EXISTING);
-            } catch (IOException e) {
-                throw new RuntimeException(e);
-            }
-            final File outOemInCache = new File(TEST_OEM_DIR, fontFile);
-            try (InputStream is = am.open(sourceInAsset)) {
-                Files.copy(is, outOemInCache.toPath(), StandardCopyOption.REPLACE_EXISTING);
-            } catch (IOException e) {
-                throw new RuntimeException(e);
-            }
+            copyAssetToFile(sourceInAsset, new File(TEST_FONT_DIR, fontFile));
+            copyAssetToFile(sourceInAsset, new File(TEST_OEM_DIR, fontFile));
+        }
+        for (final File fontFile : new File(TEST_UPDATABLE_FONT_DIR).listFiles()) {
+            fontFile.delete();
         }
     }
 
@@ -124,7 +120,20 @@
             final File outInCache = new File(TEST_FONT_DIR, fontFile);
             outInCache.delete();
             final File outOemInCache = new File(TEST_OEM_DIR, fontFile);
-            outInCache.delete();
+            outOemInCache.delete();
+        }
+        for (final File fontFile : new File(TEST_UPDATABLE_FONT_DIR).listFiles()) {
+            fontFile.delete();
+        }
+    }
+
+    private static void copyAssetToFile(String sourceInAsset, File out) {
+        final AssetManager am =
+                InstrumentationRegistry.getInstrumentation().getContext().getAssets();
+        try (InputStream is = am.open(sourceInAsset)) {
+            Files.copy(is, out.toPath(), StandardCopyOption.REPLACE_EXISTING);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
         }
     }
 
@@ -138,7 +147,7 @@
         }
 
         final FontConfig.Alias[] aliases = SystemFonts.buildSystemFallback(TEST_FONTS_XML,
-                TEST_FONT_DIR, oemCustomization, fallbackMap);
+                TEST_FONT_DIR, TEST_UPDATABLE_FONT_DIR, oemCustomization, fallbackMap);
         Typeface.initSystemDefaultTypefaces(fontMap, fallbackMap, aliases);
     }
 
@@ -835,4 +844,32 @@
                 + "</fonts-modification>";
         readFontCustomization(oemXml);
     }
+
+
+    @Test
+    public void testBuildSystemFallback_UpdatableFont() {
+        final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+                + "<familyset>"
+                + "  <family name='test'>"
+                + "    <font weight='400' style='normal'>a3em.ttf</font>"
+                + "  </family>"
+                + "</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);
+
+        final Paint paint = new Paint();
+
+        final Typeface sansSerifTypeface = fontMap.get("test");
+        assertNotNull(sansSerifTypeface);
+        paint.setTypeface(sansSerifTypeface);
+        assertEquals(GLYPH_2EM_WIDTH, paint.measureText("a"), 0.0f);
+        assertEquals(GLYPH_2EM_WIDTH, paint.measureText("b"), 0.0f);
+        assertEquals(GLYPH_2EM_WIDTH, paint.measureText("c"), 0.0f);
+    }
 }
diff --git a/core/tests/coretests/src/android/widget/TextViewOnReceiveContentTest.java b/core/tests/coretests/src/android/widget/TextViewOnReceiveContentTest.java
index 9978648..9968f79 100644
--- a/core/tests/coretests/src/android/widget/TextViewOnReceiveContentTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewOnReceiveContentTest.java
@@ -87,7 +87,7 @@
     }
 
     @Test
-    public void testGetEditorInfoMimeTypes_fallbackToCommitContent() throws Throwable {
+    public void testGetFallbackMimeTypesForAutofill() throws Throwable {
         // Configure the EditText with an EditorInfo/InputConnection that supports some image MIME
         // types.
         String[] mimeTypes = {"image/gif", "image/png"};
@@ -99,11 +99,12 @@
         onView(withId(mEditText.getId())).perform(clickOnTextAtIndex(0));
 
         // Assert that the default listener returns the MIME types declared in the EditorInfo.
-        assertThat(mDefaultReceiver.getEditorInfoMimeTypes(mEditText)).isEqualTo(mimeTypes);
+        assertThat(mDefaultReceiver.getFallbackMimeTypesForAutofill(mEditText)).isEqualTo(
+                mimeTypes);
     }
 
     @Test
-    public void testGetEditorInfoMimeTypes_fallbackToCommitContent_noMimeTypesInEditorInfo()
+    public void testGetFallbackMimeTypesForAutofill_noMimeTypesInEditorInfo()
             throws Throwable {
         // Configure the EditText with an EditorInfo/InputConnection that doesn't declare any MIME
         // types.
@@ -115,7 +116,7 @@
         onView(withId(mEditText.getId())).perform(clickOnTextAtIndex(0));
 
         // Assert that the default listener returns null as the MIME types.
-        assertThat(mDefaultReceiver.getEditorInfoMimeTypes(mEditText)).isNull();
+        assertThat(mDefaultReceiver.getFallbackMimeTypesForAutofill(mEditText)).isNull();
     }
 
     @Test
diff --git a/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java
new file mode 100644
index 0000000..e2a1064
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.BatteryConsumer;
+import android.os.SystemBatteryConsumer;
+import android.view.Display;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class AmbientDisplayPowerCalculatorTest {
+    private static final double PRECISION = 0.00001;
+
+    @Rule
+    public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
+            .setAveragePower(PowerProfile.POWER_AMBIENT_DISPLAY, 360.0);
+
+    @Test
+    public void testTimerBasedModel() {
+        BatteryStatsImpl stats = mStatsRule.getBatteryStats();
+
+        stats.noteScreenStateLocked(Display.STATE_ON, 1000, 1000, 1000);
+        stats.noteScreenStateLocked(Display.STATE_DOZE, 2000, 2000, 2000);
+        stats.noteScreenStateLocked(Display.STATE_OFF, 3000, 3000, 3000);
+
+        AmbientDisplayPowerCalculator calculator =
+                new AmbientDisplayPowerCalculator(mStatsRule.getPowerProfile());
+
+        mStatsRule.apply(calculator);
+
+        SystemBatteryConsumer consumer =
+                mStatsRule.getSystemBatteryConsumer(
+                        SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY);
+        assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE))
+                .isEqualTo(1000);
+        assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE))
+                .isWithin(PRECISION).of(0.1);
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/AudioPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/AudioPowerCalculatorTest.java
new file mode 100644
index 0000000..ed4638c
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/AudioPowerCalculatorTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.BatteryConsumer;
+import android.os.Process;
+import android.os.UidBatteryConsumer;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class AudioPowerCalculatorTest {
+    private static final double PRECISION = 0.00001;
+
+    private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
+
+    @Rule
+    public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
+            .setAveragePower(PowerProfile.POWER_AUDIO, 360.0);
+
+    @Test
+    public void testTimerBasedModel() {
+        BatteryStatsImpl.Uid uidStats = mStatsRule.getUidStats(APP_UID);
+        uidStats.noteAudioTurnedOnLocked(1000);
+        uidStats.noteAudioTurnedOffLocked(2000);
+
+        AudioPowerCalculator calculator =
+                new AudioPowerCalculator(mStatsRule.getPowerProfile());
+
+        mStatsRule.apply(calculator);
+
+        UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID);
+        assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_AUDIO))
+                .isEqualTo(1000);
+        assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_AUDIO))
+                .isWithin(PRECISION).of(0.1);
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
index bd41542..8ff318e 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -21,6 +21,8 @@
 
 @RunWith(Suite.class)
 @Suite.SuiteClasses({
+        AmbientDisplayPowerCalculatorTest.class,
+        AudioPowerCalculatorTest.class,
         BatteryStatsCpuTimesTest.class,
         BatteryStatsBackgroundStatsTest.class,
         BatteryStatsBinderCallStatsTest.class,
@@ -42,6 +44,9 @@
         BatteryStatsUserLifecycleTests.class,
         BluetoothPowerCalculatorTest.class,
         BstatsCpuTimesValidationTest.class,
+        CameraPowerCalculatorTest.class,
+        FlashlightPowerCalculatorTest.class,
+        IdlePowerCalculatorTest.class,
         KernelCpuProcStringReaderTest.class,
         KernelCpuUidActiveTimeReaderTest.class,
         KernelCpuUidBpfMapReaderTest.class,
@@ -55,6 +60,9 @@
         LongSamplingCounterArrayTest.class,
         PowerCalculatorTest.class,
         PowerProfileTest.class,
+        ScreenPowerCalculatorTest.class,
+        SystemServicePowerCalculatorTest.class,
+        VideoPowerCalculatorTest.class,
 
         com.android.internal.power.MeasuredEnergyStatsTest.class
     })
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
new file mode 100644
index 0000000..55f64f9
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.BatteryStats;
+import android.os.BatteryUsageStats;
+import android.os.BatteryUsageStatsQuery;
+import android.os.SystemBatteryConsumer;
+import android.os.UidBatteryConsumer;
+import android.util.SparseArray;
+
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+public class BatteryUsageStatsRule implements TestRule {
+    private final PowerProfile mPowerProfile;
+    private final MockClocks mMockClocks = new MockClocks();
+    private final MockBatteryStatsImpl mBatteryStats = new MockBatteryStatsImpl(mMockClocks) {
+        @Override
+        public boolean hasBluetoothActivityReporting() {
+            return true;
+        }
+    };
+
+    private BatteryUsageStats mBatteryUsageStats;
+
+    public BatteryUsageStatsRule() {
+        Context context = InstrumentationRegistry.getContext();
+        mPowerProfile = spy(new PowerProfile(context, true /* forTest */));
+        mBatteryStats.setPowerProfile(mPowerProfile);
+    }
+
+    public BatteryUsageStatsRule setAveragePower(String key, double value) {
+        when(mPowerProfile.getAveragePower(key)).thenReturn(value);
+        return this;
+    }
+
+    public BatteryUsageStatsRule setAveragePower(String key, double[] values) {
+        when(mPowerProfile.getNumElements(key)).thenReturn(values.length);
+        for (int i = 0; i < values.length; i++) {
+            when(mPowerProfile.getAveragePower(key, i)).thenReturn(values[i]);
+        }
+        return this;
+    }
+
+    @Override
+    public Statement apply(Statement base, Description description) {
+        return new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                noteOnBattery();
+                base.evaluate();
+            }
+        };
+    }
+
+    private void noteOnBattery() {
+        mBatteryStats.getOnBatteryTimeBase().setRunning(true, 0, 0);
+    }
+
+    public PowerProfile getPowerProfile() {
+        return mPowerProfile;
+    }
+
+    public MockBatteryStatsImpl getBatteryStats() {
+        return mBatteryStats;
+    }
+
+    public BatteryStatsImpl.Uid getUidStats(int uid) {
+        return mBatteryStats.getUidStatsLocked(uid);
+    }
+
+    public void setTime(long realtimeUs, long uptimeUs) {
+        mMockClocks.realtime = realtimeUs;
+        mMockClocks.uptime = uptimeUs;
+    }
+
+    void apply(PowerCalculator calculator) {
+        BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(0, 0, false);
+        SparseArray<? extends BatteryStats.Uid> uidStats = mBatteryStats.getUidStats();
+        for (int i = 0; i < uidStats.size(); i++) {
+            builder.getOrCreateUidBatteryConsumerBuilder(uidStats.valueAt(i));
+        }
+
+        calculator.calculate(builder, mBatteryStats, mMockClocks.realtime, mMockClocks.uptime,
+                BatteryUsageStatsQuery.DEFAULT, null);
+
+        mBatteryUsageStats = builder.build();
+    }
+
+    public UidBatteryConsumer getUidBatteryConsumer(int uid) {
+        for (UidBatteryConsumer ubc : mBatteryUsageStats.getUidBatteryConsumers()) {
+            if (ubc.getUid() == uid) {
+                return ubc;
+            }
+        }
+        return null;
+    }
+
+    public SystemBatteryConsumer getSystemBatteryConsumer(
+            @SystemBatteryConsumer.DrainType int drainType) {
+        for (SystemBatteryConsumer sbc : mBatteryUsageStats.getSystemBatteryConsumers()) {
+            if (sbc.getDrainType() == drainType) {
+                return sbc;
+            }
+        }
+        return null;
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
index 96eb8da..e559471 100644
--- a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
@@ -18,24 +18,17 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.Mockito.when;
-
 import android.annotation.Nullable;
 import android.os.BatteryConsumer;
-import android.os.BatteryUsageStats;
-import android.os.BatteryUsageStatsQuery;
 import android.os.Process;
 import android.os.SystemBatteryConsumer;
-import android.os.UidBatteryConsumer;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
@@ -43,83 +36,69 @@
     private static final double PRECISION = 0.00001;
     private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
 
-    @Mock
-    private PowerProfile mMockPowerProfile;
-    private MockBatteryStatsImpl mMockBatteryStats;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mMockBatteryStats = new MockBatteryStatsImpl(new MockClocks()) {
-            @Override
-            public boolean hasBluetoothActivityReporting() {
-                return true;
-            }
-        };
-        mMockBatteryStats.getOnBatteryTimeBase().setRunning(true, 100_000, 100_000);
-        when(mMockPowerProfile.getAveragePower(
-                PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE)).thenReturn(10.0);
-        when(mMockPowerProfile.getAveragePower(
-                PowerProfile.POWER_BLUETOOTH_CONTROLLER_RX)).thenReturn(50.0);
-        when(mMockPowerProfile.getAveragePower(
-                PowerProfile.POWER_BLUETOOTH_CONTROLLER_TX)).thenReturn(100.0);
-    }
+    @Rule
+    public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
+            .setAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE, 10.0)
+            .setAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_RX, 50.0)
+            .setAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_TX, 100.0);
 
     @Test
     public void testTimerBasedModel() {
-        setDurationsAndPower(
-                mMockBatteryStats.getUidStatsLocked(Process.BLUETOOTH_UID)
+        setDurationsAndPower(mStatsRule.getUidStats(Process.BLUETOOTH_UID)
                         .getOrCreateBluetoothControllerActivityLocked(),
                 1000, 2000, 3000, 0);
 
-        setDurationsAndPower(mMockBatteryStats.getUidStatsLocked(APP_UID)
+        setDurationsAndPower(mStatsRule.getUidStats(APP_UID)
                         .getOrCreateBluetoothControllerActivityLocked(),
                 4000, 5000, 6000, 0);
 
         setDurationsAndPower((BatteryStatsImpl.ControllerActivityCounterImpl)
-                        mMockBatteryStats.getBluetoothControllerActivity(),
+                        mStatsRule.getBatteryStats().getBluetoothControllerActivity(),
                 6000, 8000, 10000, 0);
 
-        BatteryUsageStats batteryUsageStats = buildBatteryUsageStats();
+        BluetoothPowerCalculator calculator =
+                new BluetoothPowerCalculator(mStatsRule.getPowerProfile());
+
+        mStatsRule.apply(calculator);
 
         assertBluetoothPowerAndDuration(
-                getUidBatteryConsumer(batteryUsageStats, Process.BLUETOOTH_UID),
+                mStatsRule.getUidBatteryConsumer(Process.BLUETOOTH_UID),
                 0.11388, 6000);
         assertBluetoothPowerAndDuration(
-                getUidBatteryConsumer(batteryUsageStats, APP_UID),
+                mStatsRule.getUidBatteryConsumer(APP_UID),
                 0.24722, 15000);
         assertBluetoothPowerAndDuration(
-                getBluetoothSystemBatteryConsumer(batteryUsageStats,
-                        SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH),
+                mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH),
                 0.15833, 9000);
     }
 
     @Test
     public void testReportedPowerBasedModel() {
-        setDurationsAndPower(
-                mMockBatteryStats.getUidStatsLocked(Process.BLUETOOTH_UID)
+        setDurationsAndPower(mStatsRule.getUidStats(Process.BLUETOOTH_UID)
                         .getOrCreateBluetoothControllerActivityLocked(),
                 1000, 2000, 3000, 360000);
 
-        setDurationsAndPower(mMockBatteryStats.getUidStatsLocked(APP_UID)
+        setDurationsAndPower(mStatsRule.getUidStats(APP_UID)
                         .getOrCreateBluetoothControllerActivityLocked(),
                 4000, 5000, 6000, 720000);
 
         setDurationsAndPower((BatteryStatsImpl.ControllerActivityCounterImpl)
-                        mMockBatteryStats.getBluetoothControllerActivity(),
+                        mStatsRule.getBatteryStats().getBluetoothControllerActivity(),
                 6000, 8000, 10000, 1260000);
 
-        BatteryUsageStats batteryUsageStats = buildBatteryUsageStats();
+        BluetoothPowerCalculator calculator =
+                new BluetoothPowerCalculator(mStatsRule.getPowerProfile());
+
+        mStatsRule.apply(calculator);
 
         assertBluetoothPowerAndDuration(
-                getUidBatteryConsumer(batteryUsageStats, Process.BLUETOOTH_UID),
+                mStatsRule.getUidBatteryConsumer(Process.BLUETOOTH_UID),
                 0.1, 6000);
         assertBluetoothPowerAndDuration(
-                getUidBatteryConsumer(batteryUsageStats, APP_UID),
+                mStatsRule.getUidBatteryConsumer(APP_UID),
                 0.2, 15000);
         assertBluetoothPowerAndDuration(
-                getBluetoothSystemBatteryConsumer(batteryUsageStats,
-                        SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH),
+                mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH),
                 0.15, 9000);
     }
 
@@ -132,38 +111,6 @@
         controllerActivity.getPowerCounter().addCountLocked(powerMaMs);
     }
 
-    private BatteryUsageStats buildBatteryUsageStats() {
-        BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(0, 0, false);
-        builder.getOrCreateUidBatteryConsumerBuilder(
-                mMockBatteryStats.getUidStatsLocked(Process.BLUETOOTH_UID));
-        builder.getOrCreateUidBatteryConsumerBuilder(
-                mMockBatteryStats.getUidStatsLocked(APP_UID));
-
-        BluetoothPowerCalculator bpc = new BluetoothPowerCalculator(mMockPowerProfile);
-        bpc.calculate(builder, mMockBatteryStats, 200_000, 200_000, BatteryUsageStatsQuery.DEFAULT,
-                null);
-        return builder.build();
-    }
-
-    private UidBatteryConsumer getUidBatteryConsumer(BatteryUsageStats batteryUsageStats, int uid) {
-        for (UidBatteryConsumer ubc : batteryUsageStats.getUidBatteryConsumers()) {
-            if (ubc.getUid() == uid) {
-                return ubc;
-            }
-        }
-        return null;
-    }
-
-    private SystemBatteryConsumer getBluetoothSystemBatteryConsumer(
-            BatteryUsageStats batteryUsageStats, int drainType) {
-        for (SystemBatteryConsumer sbc : batteryUsageStats.getSystemBatteryConsumers()) {
-            if (sbc.getDrainType() == drainType) {
-                return sbc;
-            }
-        }
-        return null;
-    }
-
     private void assertBluetoothPowerAndDuration(@Nullable BatteryConsumer batteryConsumer,
             double powerMah, int durationMs) {
         assertThat(batteryConsumer).isNotNull();
diff --git a/core/tests/coretests/src/com/android/internal/os/CameraPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/CameraPowerCalculatorTest.java
new file mode 100644
index 0000000..a21dd58
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/CameraPowerCalculatorTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.BatteryConsumer;
+import android.os.Process;
+import android.os.UidBatteryConsumer;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class CameraPowerCalculatorTest {
+    private static final double PRECISION = 0.00001;
+
+    private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
+
+    @Rule
+    public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
+            .setAveragePower(PowerProfile.POWER_CAMERA, 360.0);
+
+    @Test
+    public void testTimerBasedModel() {
+        BatteryStatsImpl.Uid uidStats = mStatsRule.getUidStats(APP_UID);
+        uidStats.noteCameraTurnedOnLocked(1000);
+        uidStats.noteCameraTurnedOffLocked(2000);
+
+        CameraPowerCalculator calculator =
+                new CameraPowerCalculator(mStatsRule.getPowerProfile());
+
+        mStatsRule.apply(calculator);
+
+        UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID);
+        assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CAMERA))
+                .isEqualTo(1000);
+        assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA))
+                .isWithin(PRECISION).of(0.1);
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/FlashlightPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/FlashlightPowerCalculatorTest.java
new file mode 100644
index 0000000..b7bbedd
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/FlashlightPowerCalculatorTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.BatteryConsumer;
+import android.os.Process;
+import android.os.UidBatteryConsumer;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class FlashlightPowerCalculatorTest {
+    private static final double PRECISION = 0.00001;
+
+    private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
+
+    @Rule
+    public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
+            .setAveragePower(PowerProfile.POWER_FLASHLIGHT, 360.0);
+
+    @Test
+    public void testTimerBasedModel() {
+        BatteryStatsImpl.Uid uidStats = mStatsRule.getUidStats(APP_UID);
+        uidStats.noteFlashlightTurnedOnLocked(1000);
+        uidStats.noteFlashlightTurnedOffLocked(2000);
+
+        FlashlightPowerCalculator calculator =
+                new FlashlightPowerCalculator(mStatsRule.getPowerProfile());
+
+        mStatsRule.apply(calculator);
+
+        UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID);
+        assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_FLASHLIGHT))
+                .isEqualTo(1000);
+        assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT))
+                .isWithin(PRECISION).of(0.1);
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/IdlePowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/IdlePowerCalculatorTest.java
new file mode 100644
index 0000000..781e725
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/IdlePowerCalculatorTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.BatteryConsumer;
+import android.os.SystemBatteryConsumer;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class IdlePowerCalculatorTest {
+    private static final double PRECISION = 0.00001;
+
+    @Rule
+    public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
+            .setAveragePower(PowerProfile.POWER_CPU_IDLE, 720.0)
+            .setAveragePower(PowerProfile.POWER_CPU_SUSPEND, 360.0);
+
+    @Test
+    public void testTimerBasedModel() {
+        mStatsRule.setTime(3_000_000, 2_000_000);
+
+        IdlePowerCalculator calculator = new IdlePowerCalculator(mStatsRule.getPowerProfile());
+
+        mStatsRule.apply(calculator);
+
+        SystemBatteryConsumer consumer =
+                mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_IDLE);
+        assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE))
+                .isEqualTo(3000);
+        assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE))
+                .isWithin(PRECISION).of(0.7);
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/MemoryPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/MemoryPowerCalculatorTest.java
new file mode 100644
index 0000000..8f21503
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/MemoryPowerCalculatorTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.BatteryConsumer;
+import android.os.SystemBatteryConsumer;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class MemoryPowerCalculatorTest {
+    private static final double PRECISION = 0.00001;
+
+    @Rule
+    public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
+            .setAveragePower(PowerProfile.POWER_MEMORY, new double[] {360.0, 720.0, 1080.0});
+
+    @Test
+    public void testTimerBasedModel() {
+        BatteryStatsImpl stats = mStatsRule.getBatteryStats();
+
+        // First update establishes a baseline
+        stats.getKernelMemoryTimerLocked(0).update(0, 1, 0);
+        stats.getKernelMemoryTimerLocked(2).update(0, 1, 0);
+
+        stats.getKernelMemoryTimerLocked(0).update(1000000, 1, 4000000);
+        stats.getKernelMemoryTimerLocked(2).update(2000000, 1, 8000000);
+
+        MemoryPowerCalculator calculator =
+                new MemoryPowerCalculator(mStatsRule.getPowerProfile());
+
+        mStatsRule.apply(calculator);
+
+        SystemBatteryConsumer consumer =
+                mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_MEMORY);
+        assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE))
+                .isEqualTo(3000);
+        assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE))
+                .isWithin(PRECISION).of(0.7);
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index c775137..fc23721 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -46,6 +46,10 @@
                 mOnBatteryTimeBase);
         mScreenDozeTimer = new BatteryStatsImpl.StopwatchTimer(clocks, null, -1, null,
                 mOnBatteryTimeBase);
+        for (int i = 0; i < mScreenBrightnessTimer.length; i++) {
+            mScreenBrightnessTimer[i] = new BatteryStatsImpl.StopwatchTimer(clocks, null, -1, null,
+                    mOnBatteryTimeBase);
+        }
         mBluetoothScanTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase);
         mBluetoothActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase, 1);
         setExternalStatsSyncLocked(new DummyExternalStatsSync());
diff --git a/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java
new file mode 100644
index 0000000..e43caa3
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.BatteryConsumer;
+import android.os.SystemBatteryConsumer;
+import android.view.Display;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ScreenPowerCalculatorTest {
+    private static final double PRECISION = 0.00001;
+
+    @Rule
+    public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
+            .setAveragePower(PowerProfile.POWER_SCREEN_ON, 360.0)
+            .setAveragePower(PowerProfile.POWER_SCREEN_FULL, 3600.0);
+
+    @Test
+    public void testTimerBasedModel() {
+        BatteryStatsImpl stats = mStatsRule.getBatteryStats();
+
+        stats.noteScreenStateLocked(Display.STATE_ON, 1000, 1000, 1000);
+        stats.noteScreenBrightnessLocked(100, 1000, 1000);
+        stats.noteScreenBrightnessLocked(200, 2000, 2000);
+        stats.noteScreenStateLocked(Display.STATE_OFF, 3000, 3000, 3000);
+
+        ScreenPowerCalculator calculator =
+                new ScreenPowerCalculator(mStatsRule.getPowerProfile());
+
+        mStatsRule.apply(calculator);
+
+        SystemBatteryConsumer consumer =
+                mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_SCREEN);
+        assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE))
+                .isEqualTo(2000);
+        assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE))
+                .isWithin(PRECISION).of(1.2);
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
index dbb36fb..a5cafb9 100644
--- a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
@@ -16,50 +16,46 @@
 
 package com.android.internal.os;
 
-import static org.junit.Assert.assertEquals;
+import static com.google.common.truth.Truth.assertThat;
 
-import android.content.Context;
-import android.os.BatteryStats;
+import android.os.BatteryConsumer;
 import android.os.Binder;
 import android.os.Process;
 
 import androidx.annotation.Nullable;
-import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.List;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class SystemServicePowerCalculatorTest {
 
-    private PowerProfile mProfile;
+    private static final double PRECISION = 0.0000001;
+
+    @Rule
+    public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule();
+
     private MockBatteryStatsImpl mMockBatteryStats;
     private MockKernelCpuUidFreqTimeReader mMockCpuUidFreqTimeReader;
     private MockSystemServerCpuThreadReader mMockSystemServerCpuThreadReader;
-    private SystemServicePowerCalculator mSystemServicePowerCalculator;
 
     @Before
     public void setUp() throws IOException {
-        Context context = InstrumentationRegistry.getContext();
-        mProfile = new PowerProfile(context, true /* forTest */);
         mMockSystemServerCpuThreadReader = new MockSystemServerCpuThreadReader();
         mMockCpuUidFreqTimeReader = new MockKernelCpuUidFreqTimeReader();
-        mMockBatteryStats = new MockBatteryStatsImpl(new MockClocks())
-                .setPowerProfile(mProfile)
+        mMockBatteryStats = mStatsRule.getBatteryStats()
                 .setSystemServerCpuThreadReader(mMockSystemServerCpuThreadReader)
                 .setKernelCpuUidFreqTimeReader(mMockCpuUidFreqTimeReader)
                 .setUserInfoProvider(new MockUserInfoProvider());
-        mMockBatteryStats.getOnBatteryTimeBase().setRunning(true, 0, 0);
-        mSystemServicePowerCalculator = new SystemServicePowerCalculator(mProfile);
     }
 
     @Test
@@ -103,15 +99,17 @@
         mMockBatteryStats.updateSystemServiceCallStats();
         mMockBatteryStats.updateSystemServerThreadStats();
 
-        BatterySipper app1 = new BatterySipper(BatterySipper.DrainType.APP,
-                mMockBatteryStats.getUidStatsLocked(workSourceUid1), 0);
-        BatterySipper app2 = new BatterySipper(BatterySipper.DrainType.APP,
-                mMockBatteryStats.getUidStatsLocked(workSourceUid2), 0);
-        mSystemServicePowerCalculator.calculate(List.of(app1, app2), mMockBatteryStats, 0, 0,
-                BatteryStats.STATS_SINCE_CHARGED, null);
+        SystemServicePowerCalculator calculator = new SystemServicePowerCalculator(
+                mStatsRule.getPowerProfile());
 
-        assertEquals(0.00016269, app1.systemServiceCpuPowerMah, 0.0000001);
-        assertEquals(0.00146426, app2.systemServiceCpuPowerMah, 0.0000001);
+        mStatsRule.apply(calculator);
+
+        assertThat(mStatsRule.getUidBatteryConsumer(workSourceUid1)
+                .getConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES))
+                .isWithin(PRECISION).of(0.00016269);
+        assertThat(mStatsRule.getUidBatteryConsumer(workSourceUid2)
+                .getConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES))
+                .isWithin(PRECISION).of(0.00146426);
     }
 
     private static class MockKernelCpuUidFreqTimeReader extends
diff --git a/core/tests/coretests/src/com/android/internal/os/VideoPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/VideoPowerCalculatorTest.java
new file mode 100644
index 0000000..39eac49
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/VideoPowerCalculatorTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.BatteryConsumer;
+import android.os.Process;
+import android.os.UidBatteryConsumer;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VideoPowerCalculatorTest {
+    private static final double PRECISION = 0.00001;
+
+    private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
+
+    @Rule
+    public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
+            .setAveragePower(PowerProfile.POWER_VIDEO, 360.0);
+
+    @Test
+    public void testTimerBasedModel() {
+        BatteryStatsImpl.Uid uidStats = mStatsRule.getUidStats(APP_UID);
+        uidStats.noteVideoTurnedOnLocked(1000);
+        uidStats.noteVideoTurnedOffLocked(2000);
+
+        VideoPowerCalculator calculator =
+                new VideoPowerCalculator(mStatsRule.getPowerProfile());
+
+        mStatsRule.apply(calculator);
+
+        UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID);
+        assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_VIDEO))
+                .isEqualTo(1000);
+        assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_VIDEO))
+                .isWithin(PRECISION).of(0.1);
+    }
+}
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
index 0782f8d..73fff72 100644
--- a/graphics/java/android/graphics/FontListParser.java
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -16,6 +16,7 @@
 
 package android.graphics;
 
+import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.fonts.FontVariationAxis;
 import android.os.Build;
@@ -25,6 +26,7 @@
 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;
@@ -41,26 +43,26 @@
     /* 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");
+        return parse(in, "/system/fonts", null);
     }
 
     /**
      * Parse the fonts.xml
      */
-    public static FontConfig parse(InputStream in, String fontDir)
-            throws XmlPullParserException, IOException {
+    public static FontConfig parse(InputStream in, String fontDir,
+            @Nullable String updatableFontDir) throws XmlPullParserException, IOException {
         try {
             XmlPullParser parser = Xml.newPullParser();
             parser.setInput(in, null);
             parser.nextTag();
-            return readFamilies(parser, fontDir);
+            return readFamilies(parser, fontDir, updatableFontDir);
         } finally {
             in.close();
         }
     }
 
-    private static FontConfig readFamilies(XmlPullParser parser, String fontDir)
-            throws XmlPullParserException, IOException {
+    private static FontConfig readFamilies(XmlPullParser parser, String fontDir,
+            @Nullable String updatableFontDir) throws XmlPullParserException, IOException {
         List<FontConfig.Family> families = new ArrayList<>();
         List<FontConfig.Alias> aliases = new ArrayList<>();
 
@@ -69,7 +71,7 @@
             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
             String tag = parser.getName();
             if (tag.equals("family")) {
-                families.add(readFamily(parser, fontDir));
+                families.add(readFamily(parser, fontDir, updatableFontDir));
             } else if (tag.equals("alias")) {
                 aliases.add(readAlias(parser));
             } else {
@@ -83,8 +85,8 @@
     /**
      * Reads a family element
      */
-    public static FontConfig.Family readFamily(XmlPullParser parser, String fontDir)
-            throws XmlPullParserException, IOException {
+    public static FontConfig.Family readFamily(XmlPullParser parser, String fontDir,
+            @Nullable String updatableFontDir) throws XmlPullParserException, IOException {
         final String name = parser.getAttributeValue(null, "name");
         final String lang = parser.getAttributeValue("", "lang");
         final String variant = parser.getAttributeValue(null, "variant");
@@ -93,7 +95,7 @@
             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
             final String tag = parser.getName();
             if (tag.equals("font")) {
-                fonts.add(readFont(parser, fontDir));
+                fonts.add(readFont(parser, fontDir, updatableFontDir));
             } else {
                 skip(parser);
             }
@@ -114,8 +116,8 @@
     private static final Pattern FILENAME_WHITESPACE_PATTERN =
             Pattern.compile("^[ \\n\\r\\t]+|[ \\n\\r\\t]+$");
 
-    private static FontConfig.Font readFont(XmlPullParser parser, String fontDir)
-            throws XmlPullParserException, IOException {
+    private static FontConfig.Font readFont(XmlPullParser parser, String fontDir,
+            @Nullable String updatableFontDir) throws XmlPullParserException, IOException {
         String indexStr = parser.getAttributeValue(null, "index");
         int index = indexStr == null ? 0 : Integer.parseInt(indexStr);
         List<FontVariationAxis> axes = new ArrayList<FontVariationAxis>();
@@ -137,10 +139,22 @@
             }
         }
         String sanitizedName = FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll("");
-        return new FontConfig.Font(fontDir + sanitizedName, index, axes.toArray(
+        String fontName = findFontFile(sanitizedName, fontDir, updatableFontDir);
+        return new FontConfig.Font(fontName, index, axes.toArray(
                 new FontVariationAxis[axes.size()]), weight, isItalic, 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;
+            }
+        }
+        return fontDir + fileName;
+    }
+
     private static FontVariationAxis readAxis(XmlPullParser parser)
             throws XmlPullParserException, IOException {
         String tagStr = parser.getAttributeValue(null, "tag");
diff --git a/graphics/java/android/graphics/fonts/FontCustomizationParser.java b/graphics/java/android/graphics/fonts/FontCustomizationParser.java
index 0291d74..f95da82 100644
--- a/graphics/java/android/graphics/fonts/FontCustomizationParser.java
+++ b/graphics/java/android/graphics/fonts/FontCustomizationParser.java
@@ -97,7 +97,7 @@
             throw new IllegalArgumentException("customizationType must be specified");
         }
         if (customizationType.equals("new-named-family")) {
-            out.mAdditionalNamedFamilies.add(FontListParser.readFamily(parser, fontDir));
+            out.mAdditionalNamedFamilies.add(FontListParser.readFamily(parser, fontDir, null));
         } else {
             throw new IllegalArgumentException("Unknown customizationType=" + customizationType);
         }
diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java
index fb6ea99..16a53c2 100644
--- a/graphics/java/android/graphics/fonts/SystemFonts.java
+++ b/graphics/java/android/graphics/fonts/SystemFonts.java
@@ -91,7 +91,9 @@
         final FontCustomizationParser.Result oemCustomization =
                 readFontCustomization("/product/etc/fonts_customization.xml", "/product/fonts/");
         Map<String, FontFamily[]> map = new ArrayMap<>();
-        buildSystemFallback("/system/etc/fonts.xml", "/system/fonts/", oemCustomization, map);
+        // TODO: use updated fonts
+        buildSystemFallback("/system/etc/fonts.xml", "/system/fonts/", null /* updatableFontDir */,
+                oemCustomization, map);
         Set<Font> res = new HashSet<>();
         for (FontFamily[] families : map.values()) {
             for (FontFamily family : families) {
@@ -226,13 +228,7 @@
     }
 
     /**
-     * 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 fallbackMap An output system fallback map. Caller must pass empty map.
-     * @return a list of aliases
+     * @see #buildSystemFallback(String, String, String, FontCustomizationParser.Result, Map)
      * @hide
      */
     @VisibleForTesting
@@ -240,9 +236,31 @@
             @NonNull String fontDir,
             @NonNull FontCustomizationParser.Result oemCustomization,
             @NonNull Map<String, FontFamily[]> fallbackMap) {
+        return buildSystemFallback(xmlPath, fontDir, null /* updatableFontDir */,
+                oemCustomization, fallbackMap);
+    }
+
+    /**
+     * 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
+     * @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);
+            final FontConfig fontConfig = FontListParser.parse(fontsIn, fontDir, updatableFontDir);
 
             final HashMap<String, ByteBuffer> bufferCache = new HashMap<String, ByteBuffer>();
             final FontConfig.Family[] xmlFamilies = fontConfig.getFamilies();
@@ -306,11 +324,17 @@
     /** @hide */
     public static @NonNull Pair<FontConfig.Alias[], Map<String, FontFamily[]>>
             initializePreinstalledFonts() {
+        return initializeSystemFonts(null);
+    }
+
+    /** @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/",
-                oemCustomization, map);
+                updatableFontDir, oemCustomization, map);
         synchronized (LOCK) {
             sFamilyMap = map;
         }
diff --git a/identity/java/android/security/identity/Util.java b/identity/java/android/security/identity/Util.java
index 6eefeb8..e56bd51 100644
--- a/identity/java/android/security/identity/Util.java
+++ b/identity/java/android/security/identity/Util.java
@@ -16,6 +16,8 @@
 
 package android.security.identity;
 
+import android.annotation.NonNull;
+
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.security.InvalidKeyException;
@@ -28,7 +30,10 @@
 import javax.crypto.Mac;
 import javax.crypto.spec.SecretKeySpec;
 
-class Util {
+/**
+ * @hide
+ */
+public class Util {
     private static final String TAG = "Util";
 
     static int[] integerCollectionToArray(Collection<Integer> collection) {
@@ -91,8 +96,9 @@
      *                     255.DigestSize, where DigestSize is the size of the underlying HMAC.
      * @return size pseudorandom bytes.
      */
-    static byte[] computeHkdf(
-            String macAlgorithm, final byte[] ikm, final byte[] salt, final byte[] info, int size) {
+    @NonNull public static byte[] computeHkdf(
+            @NonNull String macAlgorithm, @NonNull final byte[] ikm, @NonNull final byte[] salt,
+            @NonNull final byte[] info, int size) {
         Mac mac = null;
         try {
             mac = Mac.getInstance(macAlgorithm);
@@ -137,4 +143,5 @@
         }
     }
 
+    private Util() {}
 }
diff --git a/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json b/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json
index 4070829..0290d9f 100644
--- a/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json
+++ b/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json
@@ -7,24 +7,12 @@
       "group": "WM_SHELL_TASK_ORG",
       "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
     },
-    "-1534364071": {
-      "message": "onTransitionReady %s: %s",
-      "level": "VERBOSE",
-      "group": "WM_SHELL_TRANSITIONS",
-      "at": "com\/android\/wm\/shell\/Transitions.java"
-    },
     "-1501874464": {
       "message": "Fullscreen Task Appeared: #%d",
       "level": "VERBOSE",
       "group": "WM_SHELL_TASK_ORG",
       "at": "com\/android\/wm\/shell\/FullscreenTaskListener.java"
     },
-    "-1480787369": {
-      "message": "Transition requested: type=%d %s",
-      "level": "VERBOSE",
-      "group": "WM_SHELL_TRANSITIONS",
-      "at": "com\/android\/wm\/shell\/Transitions.java"
-    },
     "-1382704050": {
       "message": "Display removed: %d",
       "level": "VERBOSE",
@@ -97,12 +85,6 @@
       "group": "WM_SHELL_TASK_ORG",
       "at": "com\/android\/wm\/shell\/apppairs\/AppPairsController.java"
     },
-    "-191422040": {
-      "message": "Transition animations finished, notifying core %s",
-      "level": "VERBOSE",
-      "group": "WM_SHELL_TRANSITIONS",
-      "at": "com\/android\/wm\/shell\/Transitions.java"
-    },
     "157713005": {
       "message": "Task info changed taskId=%d",
       "level": "VERBOSE",
@@ -115,6 +97,12 @@
       "group": "WM_SHELL_DRAG_AND_DROP",
       "at": "com\/android\/wm\/shell\/draganddrop\/DropOutlineDrawable.java"
     },
+    "325110414": {
+      "message": "Transition animations finished, notifying core %s",
+      "level": "VERBOSE",
+      "group": "WM_SHELL_TRANSITIONS",
+      "at": "com\/android\/wm\/shell\/transition\/Transitions.java"
+    },
     "375908576": {
       "message": "Clip description: handlingDrag=%b itemCount=%d mimeTypes=%s",
       "level": "VERBOSE",
@@ -145,6 +133,12 @@
       "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",
@@ -169,6 +163,12 @@
       "group": "WM_SHELL_TASK_ORG",
       "at": "com\/android\/wm\/shell\/legacysplitscreen\/LegacySplitScreenTaskListener.java"
     },
+    "1070270131": {
+      "message": "onTransitionReady %s: %s",
+      "level": "VERBOSE",
+      "group": "WM_SHELL_TRANSITIONS",
+      "at": "com\/android\/wm\/shell\/transition\/Transitions.java"
+    },
     "1079041527": {
       "message": "incrementPool size=%d",
       "level": "VERBOSE",
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 8817f8a..0146b72 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java
@@ -30,6 +30,7 @@
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.transition.Transitions;
 
 import java.io.PrintWriter;
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
index 0056761..0cee0a2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
@@ -24,9 +24,9 @@
 import com.android.wm.shell.common.annotations.ExternalThread;
 import com.android.wm.shell.draganddrop.DragAndDropController;
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
+import com.android.wm.shell.transition.Transitions;
 
 import java.util.Optional;
-import java.util.concurrent.TimeUnit;
 
 /**
  * The entry point implementation into the shell for initializing shell internal state.
@@ -41,6 +41,7 @@
     private final Optional<AppPairs> mAppPairsOptional;
     private final FullscreenTaskListener mFullscreenTaskListener;
     private final ShellExecutor mMainExecutor;
+    private final Transitions mTransitions;
 
     private final InitImpl mImpl = new InitImpl();
 
@@ -50,6 +51,7 @@
             Optional<LegacySplitScreen> legacySplitScreenOptional,
             Optional<AppPairs> appPairsOptional,
             FullscreenTaskListener fullscreenTaskListener,
+            Transitions transitions,
             ShellExecutor mainExecutor) {
         return new ShellInitImpl(displayImeController,
                 dragAndDropController,
@@ -57,6 +59,7 @@
                 legacySplitScreenOptional,
                 appPairsOptional,
                 fullscreenTaskListener,
+                transitions,
                 mainExecutor).mImpl;
     }
 
@@ -66,6 +69,7 @@
             Optional<LegacySplitScreen> legacySplitScreenOptional,
             Optional<AppPairs> appPairsOptional,
             FullscreenTaskListener fullscreenTaskListener,
+            Transitions transitions,
             ShellExecutor mainExecutor) {
         mDisplayImeController = displayImeController;
         mDragAndDropController = dragAndDropController;
@@ -73,6 +77,7 @@
         mLegacySplitScreenOptional = legacySplitScreenOptional;
         mAppPairsOptional = appPairsOptional;
         mFullscreenTaskListener = fullscreenTaskListener;
+        mTransitions = transitions;
         mMainExecutor = mainExecutor;
     }
 
@@ -89,6 +94,10 @@
 
         // Bind the splitscreen impl to the drag drop controller
         mDragAndDropController.initialize(mLegacySplitScreenOptional);
+
+        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+            mTransitions.register(mShellTaskOrganizer);
+        }
     }
 
     @ExternalThread
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java
index 9e1f0a2..a785cff 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java
@@ -43,7 +43,6 @@
 import com.android.internal.policy.DividerSnapAlgorithm;
 import com.android.wm.shell.R;
 import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.Transitions;
 import com.android.wm.shell.common.DisplayChangeController;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayImeController;
@@ -54,6 +53,7 @@
 import com.android.wm.shell.common.TaskStackListenerCallback;
 import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.transition.Transitions;
 
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java
index 3ed070b..5a493c2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java
@@ -38,8 +38,8 @@
 
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.Transitions;
 import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.transition.Transitions;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
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 93520c0..94b2cc0 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
@@ -38,9 +38,9 @@
 import android.window.TransitionInfo;
 import android.window.WindowContainerTransaction;
 
-import com.android.wm.shell.Transitions;
 import com.android.wm.shell.common.TransactionPool;
 import com.android.wm.shell.common.annotations.ExternalThread;
+import com.android.wm.shell.transition.Transitions;
 
 import java.util.ArrayList;
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java
index 90a8de0..ad05e6d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java
@@ -39,8 +39,8 @@
 import android.window.WindowOrganizer;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.wm.shell.Transitions;
 import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.transition.Transitions;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
index e32d3b9..df7c753 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
@@ -83,8 +83,18 @@
 
     private ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
             ThreadLocal.withInitial(() -> {
-                FrameCallbackScheduler scheduler = runnable ->
+                final Looper initialLooper = Looper.myLooper();
+                final FrameCallbackScheduler scheduler = new FrameCallbackScheduler() {
+                    @Override
+                    public void postFrameCallback(@androidx.annotation.NonNull Runnable runnable) {
                         Choreographer.getSfInstance().postFrameCallback(t -> runnable.run());
+                    }
+
+                    @Override
+                    public boolean isCurrentThread() {
+                        return Looper.myLooper() == initialLooper;
+                    }
+                };
                 AnimationHandler handler = new AnimationHandler(scheduler);
                 return handler;
             });
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
deleted file mode 100644
index ffa6c99..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
+++ /dev/null
@@ -1,550 +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.wm.shell.pip.tv;
-
-import static android.app.ActivityTaskManager.INVALID_STACK_ID;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.content.Intent.ACTION_MEDIA_RESOURCE_GRANTED;
-
-import static com.android.wm.shell.pip.tv.PipNotification.ACTION_CLOSE;
-import static com.android.wm.shell.pip.tv.PipNotification.ACTION_MENU;
-
-import android.app.ActivityManager;
-import android.app.ActivityTaskManager;
-import android.app.ActivityTaskManager.RootTaskInfo;
-import android.app.IActivityTaskManager;
-import android.app.RemoteAction;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ParceledListSlice;
-import android.content.res.Configuration;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.DisplayInfo;
-
-import com.android.wm.shell.R;
-import com.android.wm.shell.WindowManagerShellWrapper;
-import com.android.wm.shell.common.TaskStackListenerCallback;
-import com.android.wm.shell.common.TaskStackListenerImpl;
-import com.android.wm.shell.pip.PinnedStackListenerForwarder;
-import com.android.wm.shell.pip.Pip;
-import com.android.wm.shell.pip.PipBoundsAlgorithm;
-import com.android.wm.shell.pip.PipBoundsState;
-import com.android.wm.shell.pip.PipMediaController;
-import com.android.wm.shell.pip.PipTaskOrganizer;
-
-import java.util.Objects;
-
-/**
- * Manages the picture-in-picture (PIP) UI and states.
- */
-public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallback,
-        TvPipMenuController.Delegate {
-    private static final String TAG = "TvPipController";
-    static final boolean DEBUG = false;
-
-    /**
-     * Unknown or invalid state
-     */
-    public static final int STATE_UNKNOWN = -1;
-    /**
-     * State when there's no PIP.
-     */
-    public static final int STATE_NO_PIP = 0;
-    /**
-     * State when PIP is shown. This is used as default PIP state.
-     */
-    public static final int STATE_PIP = 1;
-    /**
-     * State when PIP menu dialog is shown.
-     */
-    public static final int STATE_PIP_MENU = 2;
-
-    private static final int TASK_ID_NO_PIP = -1;
-    private static final int INVALID_RESOURCE_TYPE = -1;
-
-    private final Context mContext;
-    private final PipBoundsState mPipBoundsState;
-    private final PipBoundsAlgorithm mPipBoundsAlgorithm;
-    private final PipTaskOrganizer mPipTaskOrganizer;
-    private final PipMediaController mPipMediaController;
-    private final TvPipMenuController mTvPipMenuController;
-    private final PipNotification mPipNotification;
-
-    private IActivityTaskManager mActivityTaskManager;
-    private int mState = STATE_NO_PIP;
-    private final Handler mHandler = new Handler();
-    private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED;
-    private int mPipTaskId = TASK_ID_NO_PIP;
-    private int mPinnedStackId = INVALID_STACK_ID;
-    private String[] mLastPackagesResourceGranted;
-    private ParceledListSlice<RemoteAction> mCustomActions;
-    private WindowManagerShellWrapper mWindowManagerShellWrapper;
-    private int mResizeAnimationDuration;
-
-    // Used to calculate the movement bounds
-    private final DisplayInfo mTmpDisplayInfo = new DisplayInfo();
-    private final Rect mTmpInsetBounds = new Rect();
-
-    // Keeps track of the IME visibility to adjust the PiP when the IME is visible
-    private boolean mImeVisible;
-    private int mImeHeightAdjustment;
-
-    private final Runnable mClosePipRunnable = this::closePip;
-    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (DEBUG) {
-                Log.d(TAG, "mBroadcastReceiver, action: " + intent.getAction());
-            }
-            switch (intent.getAction()) {
-                case ACTION_MENU:
-                    showPictureInPictureMenu();
-                    break;
-                case ACTION_CLOSE:
-                    closePip();
-                    break;
-                case ACTION_MEDIA_RESOURCE_GRANTED:
-                    String[] packageNames = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
-                    int resourceType = intent.getIntExtra(Intent.EXTRA_MEDIA_RESOURCE_TYPE,
-                            INVALID_RESOURCE_TYPE);
-                    if (packageNames != null && packageNames.length > 0
-                            && resourceType == Intent.EXTRA_MEDIA_RESOURCE_TYPE_VIDEO_CODEC) {
-                        handleMediaResourceGranted(packageNames);
-                    }
-                    break;
-            }
-        }
-    };
-
-    private final PinnedStackListenerForwarder.PinnedStackListener mPinnedStackListener =
-            new PipControllerPinnedStackListener();
-
-    @Override
-    public void registerSessionListenerForCurrentUser() {
-        mPipMediaController.registerSessionListenerForCurrentUser();
-    }
-
-    /**
-     * Handler for messages from the PIP controller.
-     */
-    private class PipControllerPinnedStackListener extends
-            PinnedStackListenerForwarder.PinnedStackListener {
-        @Override
-        public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
-            mPipBoundsState.setImeVisibility(imeVisible, imeHeight);
-            if (mState == STATE_PIP) {
-                if (mImeVisible != imeVisible) {
-                    if (imeVisible) {
-                        // Save the IME height adjustment, and offset to not occlude the IME
-                        mPipBoundsState.getNormalBounds().offset(0, -imeHeight);
-                        mImeHeightAdjustment = imeHeight;
-                    } else {
-                        // Apply the inverse adjustment when the IME is hidden
-                        mPipBoundsState.getNormalBounds().offset(0, mImeHeightAdjustment);
-                    }
-                    mImeVisible = imeVisible;
-                    resizePinnedStack(STATE_PIP);
-                }
-            }
-        }
-
-        @Override
-        public void onMovementBoundsChanged(boolean fromImeAdjustment) {
-            mTmpDisplayInfo.copyFrom(mPipBoundsState.getDisplayInfo());
-            mPipBoundsAlgorithm.getInsetBounds(mTmpInsetBounds);
-        }
-
-        @Override
-        public void onActionsChanged(ParceledListSlice<RemoteAction> actions) {
-            mCustomActions = actions;
-            mTvPipMenuController.setAppActions(mCustomActions);
-        }
-    }
-
-    public PipController(Context context,
-            PipBoundsState pipBoundsState,
-            PipBoundsAlgorithm pipBoundsAlgorithm,
-            PipTaskOrganizer pipTaskOrganizer,
-            TvPipMenuController tvPipMenuController,
-            PipMediaController pipMediaController,
-            PipNotification pipNotification,
-            TaskStackListenerImpl taskStackListener,
-            WindowManagerShellWrapper windowManagerShellWrapper) {
-        mContext = context;
-        mPipBoundsState = pipBoundsState;
-        mPipNotification = pipNotification;
-        mPipBoundsAlgorithm = pipBoundsAlgorithm;
-        mPipMediaController = pipMediaController;
-        mTvPipMenuController = tvPipMenuController;
-        mTvPipMenuController.setDelegate(this);
-        // Ensure that we have the display info in case we get calls to update the bounds
-        // before the listener calls back
-        final DisplayInfo displayInfo = new DisplayInfo();
-        context.getDisplay().getDisplayInfo(displayInfo);
-        mPipBoundsState.setDisplayInfo(displayInfo);
-
-        mResizeAnimationDuration = context.getResources()
-                .getInteger(R.integer.config_pipResizeAnimationDuration);
-        mPipTaskOrganizer = pipTaskOrganizer;
-        mPipTaskOrganizer.registerPipTransitionCallback(this);
-        mActivityTaskManager = ActivityTaskManager.getService();
-
-        final IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(ACTION_CLOSE);
-        intentFilter.addAction(ACTION_MENU);
-        intentFilter.addAction(ACTION_MEDIA_RESOURCE_GRANTED);
-        mContext.registerReceiver(mBroadcastReceiver, intentFilter, UserHandle.USER_ALL);
-
-        // Initialize the last orientation and apply the current configuration
-        Configuration initialConfig = mContext.getResources().getConfiguration();
-        mLastOrientation = initialConfig.orientation;
-        loadConfigurationsAndApply(initialConfig);
-
-        mWindowManagerShellWrapper = windowManagerShellWrapper;
-        try {
-            mWindowManagerShellWrapper.addPinnedStackListener(mPinnedStackListener);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to register pinned stack listener", e);
-        }
-
-        // Handle for system task stack changes.
-        taskStackListener.addListener(
-                new TaskStackListenerCallback() {
-                    @Override
-                    public void onTaskStackChanged() {
-                        PipController.this.onTaskStackChanged();
-                    }
-
-                    @Override
-                    public void onActivityPinned(String packageName, int userId, int taskId,
-                            int stackId) {
-                        PipController.this.onActivityPinned(packageName);
-                    }
-
-                    @Override
-                    public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
-                            boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
-                        PipController.this.onActivityRestartAttempt(task, clearedTask);
-                    }
-                });
-    }
-
-    private void loadConfigurationsAndApply(Configuration newConfig) {
-        if (mLastOrientation != newConfig.orientation) {
-            // Don't resize the pinned stack on orientation change. TV does not care about this case
-            // and this could clobber the existing animation to the new bounds calculated by WM.
-            mLastOrientation = newConfig.orientation;
-            return;
-        }
-
-        final Rect menuBounds = Rect.unflattenFromString(
-                mContext.getResources().getString(R.string.pip_menu_bounds));
-        mPipBoundsState.setExpandedBounds(menuBounds);
-
-        resizePinnedStack(getPinnedTaskInfo() == null ? STATE_NO_PIP : STATE_PIP);
-    }
-
-    /**
-     * Updates the PIP per configuration changed.
-     */
-    @Override
-    public void onConfigurationChanged(Configuration newConfig) {
-        loadConfigurationsAndApply(newConfig);
-        mPipNotification.onConfigurationChanged(mContext);
-    }
-
-    /**
-     * Shows the picture-in-picture menu if an activity is in picture-in-picture mode.
-     */
-    public void showPictureInPictureMenu() {
-        if (DEBUG) Log.d(TAG, "showPictureInPictureMenu(), current state=" + getStateDescription());
-
-        if (getState() == STATE_PIP) {
-            resizePinnedStack(STATE_PIP_MENU);
-        }
-    }
-
-    /**
-     * Closes PIP (PIPed activity and PIP system UI).
-     */
-    @Override
-    public void closePip() {
-        if (DEBUG) Log.d(TAG, "closePip(), current state=" + getStateDescription());
-
-        closePipInternal(true);
-    }
-
-    private void closePipInternal(boolean removePipStack) {
-        if (DEBUG) {
-            Log.d(TAG,
-                    "closePipInternal() removePipStack=" + removePipStack + ", current state="
-                            + getStateDescription());
-        }
-
-        mState = STATE_NO_PIP;
-        mPipTaskId = TASK_ID_NO_PIP;
-        if (removePipStack) {
-            try {
-                mActivityTaskManager.removeTask(mPinnedStackId);
-            } catch (RemoteException e) {
-                Log.e(TAG, "removeTask failed", e);
-            } finally {
-                mPinnedStackId = INVALID_STACK_ID;
-            }
-        }
-        mPipNotification.dismiss();
-        mTvPipMenuController.hideMenu();
-        mHandler.removeCallbacks(mClosePipRunnable);
-    }
-
-    @Override
-    public void movePipToNormalPosition() {
-        resizePinnedStack(PipController.STATE_PIP);
-    }
-
-    /**
-     * Moves the PIPed activity to the fullscreen and closes PIP system UI.
-     */
-    @Override
-    public void movePipToFullscreen() {
-        if (DEBUG) Log.d(TAG, "movePipToFullscreen(), current state=" + getStateDescription());
-
-        mPipTaskId = TASK_ID_NO_PIP;
-        mTvPipMenuController.hideMenu();
-        mPipNotification.dismiss();
-
-        resizePinnedStack(STATE_NO_PIP);
-    }
-
-    private void onActivityPinned(String packageName) {
-        final RootTaskInfo taskInfo = getPinnedTaskInfo();
-        if (DEBUG) Log.d(TAG, "onActivityPinned, task=" + taskInfo);
-        if (taskInfo == null) {
-            Log.w(TAG, "Cannot find pinned stack");
-            return;
-        }
-
-        // At this point PipBoundsState knows the correct aspect ratio for this pinned task, so we
-        // use PipBoundsAlgorithm to calculate the normal bounds for the task (PipBoundsAlgorithm
-        // will query PipBoundsState for the aspect ratio) and pass the bounds over to the
-        // PipBoundsState.
-        mPipBoundsState.setNormalBounds(mPipBoundsAlgorithm.getNormalBounds());
-
-        mPinnedStackId = taskInfo.taskId;
-        mPipTaskId = taskInfo.childTaskIds[taskInfo.childTaskIds.length - 1];
-
-        // Set state to STATE_PIP so we show it when the pinned stack animation ends.
-        mState = STATE_PIP;
-        mPipMediaController.onActivityPinned();
-        mPipNotification.show(packageName);
-    }
-
-    private void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
-            boolean clearedTask) {
-        if (task.getWindowingMode() != WINDOWING_MODE_PINNED) {
-            return;
-        }
-        if (DEBUG) Log.d(TAG, "onPinnedActivityRestartAttempt()");
-
-        // If PIPed activity is launched again by Launcher or intent, make it fullscreen.
-        movePipToFullscreen();
-    }
-
-    private void onTaskStackChanged() {
-        if (DEBUG) Log.d(TAG, "onTaskStackChanged()");
-
-        if (getState() != STATE_NO_PIP) {
-            boolean hasPip = false;
-
-            RootTaskInfo taskInfo = getPinnedTaskInfo();
-            if (taskInfo == null || taskInfo.childTaskIds == null) {
-                Log.w(TAG, "There is nothing in pinned stack");
-                closePipInternal(false);
-                return;
-            }
-            for (int i = taskInfo.childTaskIds.length - 1; i >= 0; --i) {
-                if (taskInfo.childTaskIds[i] == mPipTaskId) {
-                    // PIP task is still alive.
-                    hasPip = true;
-                    break;
-                }
-            }
-            if (!hasPip) {
-                // PIP task doesn't exist anymore in PINNED_STACK.
-                closePipInternal(true);
-                return;
-            }
-        }
-        if (getState() == STATE_PIP) {
-            if (!Objects.equals(mPipBoundsState.getBounds(), mPipBoundsState.getNormalBounds())) {
-                resizePinnedStack(STATE_PIP);
-            }
-        }
-    }
-
-    /**
-     * Resize the Pip to the appropriate size for the input state.
-     *
-     * @param state In Pip state also used to determine the new size for the Pip.
-     */
-    public void resizePinnedStack(int state) {
-        if (DEBUG) {
-            Log.d(TAG, "resizePinnedStack() state=" + stateToName(state) + ", current state="
-                    + getStateDescription(), new Exception());
-        }
-        final boolean wasStateNoPip = (mState == STATE_NO_PIP);
-        mTvPipMenuController.hideMenu();
-        mState = state;
-        final Rect newBounds;
-        switch (mState) {
-            case STATE_NO_PIP:
-                newBounds = null;
-                // If the state was already STATE_NO_PIP, then do not resize the stack below as it
-                // will not exist
-                if (wasStateNoPip) {
-                    return;
-                }
-                break;
-            case STATE_PIP_MENU:
-                newBounds = mPipBoundsState.getExpandedBounds();
-                break;
-            case STATE_PIP: // fallthrough
-            default:
-                newBounds = mPipBoundsState.getNormalBounds();
-                break;
-        }
-        if (newBounds != null) {
-            mPipTaskOrganizer.scheduleAnimateResizePip(newBounds, mResizeAnimationDuration, null);
-        } else {
-            mPipTaskOrganizer.exitPip(mResizeAnimationDuration);
-        }
-    }
-
-    /**
-     * @return the current state.
-     */
-    private int getState() {
-        return mState;
-    }
-
-    private void showPipMenu() {
-        if (DEBUG) Log.d(TAG, "showPipMenu(), current state=" + getStateDescription());
-
-        mState = STATE_PIP_MENU;
-        mTvPipMenuController.showMenu();
-    }
-
-    /**
-     * Returns {@code true} if PIP is shown.
-     */
-    public boolean isPipShown() {
-        return mState != STATE_NO_PIP;
-    }
-
-    private RootTaskInfo getPinnedTaskInfo() {
-        RootTaskInfo taskInfo = null;
-        try {
-            taskInfo = ActivityTaskManager.getService().getRootTaskInfo(
-                    WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
-        } catch (RemoteException e) {
-            Log.e(TAG, "getRootTaskInfo failed", e);
-        }
-        if (DEBUG) Log.d(TAG, "getPinnedTaskInfo(), taskInfo=" + taskInfo);
-        return taskInfo;
-    }
-
-    private void handleMediaResourceGranted(String[] packageNames) {
-        if (getState() == STATE_NO_PIP) {
-            mLastPackagesResourceGranted = packageNames;
-        } else {
-            boolean requestedFromLastPackages = false;
-            if (mLastPackagesResourceGranted != null) {
-                for (String packageName : mLastPackagesResourceGranted) {
-                    for (String newPackageName : packageNames) {
-                        if (TextUtils.equals(newPackageName, packageName)) {
-                            requestedFromLastPackages = true;
-                            break;
-                        }
-                    }
-                }
-            }
-            mLastPackagesResourceGranted = packageNames;
-            if (!requestedFromLastPackages) {
-                closePip();
-            }
-        }
-    }
-
-    @Override
-    public void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) {
-    }
-
-    PipMediaController getPipMediaController() {
-        return mPipMediaController;
-    }
-
-    @Override
-    public void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds) {
-    }
-
-    @Override
-    public void onPipTransitionFinished(ComponentName activity, int direction) {
-        onPipTransitionFinishedOrCanceled();
-    }
-
-    @Override
-    public void onPipTransitionCanceled(ComponentName activity, int direction) {
-        onPipTransitionFinishedOrCanceled();
-    }
-
-    private void onPipTransitionFinishedOrCanceled() {
-        if (DEBUG) Log.d(TAG, "onPipTransitionFinishedOrCanceled()");
-
-        if (getState() == STATE_PIP_MENU) {
-            showPipMenu();
-        }
-    }
-
-    private String getStateDescription() {
-        return stateToName(mState);
-    }
-
-    private static String stateToName(int state) {
-        switch (state) {
-            case STATE_NO_PIP:
-                return "NO_PIP";
-
-            case STATE_PIP:
-                return "PIP";
-
-            case STATE_PIP_MENU:
-                return "PIP_MENU";
-
-            default:
-                return "UNKNOWN(" + state + ")";
-        }
-    }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
new file mode 100644
index 0000000..8bc60f9
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
@@ -0,0 +1,421 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.pip.tv;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+
+import android.annotation.IntDef;
+import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
+import android.app.RemoteAction;
+import android.app.TaskInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ParceledListSlice;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.DisplayInfo;
+
+import com.android.wm.shell.R;
+import com.android.wm.shell.WindowManagerShellWrapper;
+import com.android.wm.shell.common.TaskStackListenerCallback;
+import com.android.wm.shell.common.TaskStackListenerImpl;
+import com.android.wm.shell.pip.PinnedStackListenerForwarder;
+import com.android.wm.shell.pip.Pip;
+import com.android.wm.shell.pip.PipBoundsAlgorithm;
+import com.android.wm.shell.pip.PipBoundsState;
+import com.android.wm.shell.pip.PipMediaController;
+import com.android.wm.shell.pip.PipTaskOrganizer;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Manages the picture-in-picture (PIP) UI and states.
+ */
+public class TvPipController implements Pip, PipTaskOrganizer.PipTransitionCallback,
+        TvPipMenuController.Delegate, TvPipNotificationController.Delegate {
+    private static final String TAG = "TvPipController";
+    static final boolean DEBUG = true;
+
+    private static final int NONEXISTENT_TASK_ID = -1;
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "STATE_" }, value = {
+            STATE_NO_PIP,
+            STATE_PIP,
+            STATE_PIP_MENU
+    })
+    public @interface State {}
+
+    /**
+     * State when there is no applications in Pip.
+     */
+    private static final int STATE_NO_PIP = 0;
+    /**
+     * State when there is an applications in Pip and the Pip window located at its "normal" place
+     * (usually the bottom right corner).
+     */
+    private static final int STATE_PIP = 1;
+    /**
+     * State when there is an applications in Pip and the Pip menu is open. In this state Pip window
+     * is usually moved from its "normal" position on the screen to the "menu" position - which is
+     * often at the middle of the screen, and gets slightly scaled up.
+     */
+    private static final int STATE_PIP_MENU = 2;
+
+    private final Context mContext;
+
+    private final PipBoundsState mPipBoundsState;
+    private final PipBoundsAlgorithm mPipBoundsAlgorithm;
+    private final PipTaskOrganizer mPipTaskOrganizer;
+    private final PipMediaController mPipMediaController;
+    private final TvPipNotificationController mPipNotificationController;
+    private final TvPipMenuController mTvPipMenuController;
+
+    private @State int mState = STATE_NO_PIP;
+    private int mPinnedTaskId = NONEXISTENT_TASK_ID;
+
+    private int mResizeAnimationDuration;
+
+    public TvPipController(
+            Context context,
+            PipBoundsState pipBoundsState,
+            PipBoundsAlgorithm pipBoundsAlgorithm,
+            PipTaskOrganizer pipTaskOrganizer,
+            TvPipMenuController tvPipMenuController,
+            PipMediaController pipMediaController,
+            TvPipNotificationController pipNotificationController,
+            TaskStackListenerImpl taskStackListener,
+            WindowManagerShellWrapper wmShell) {
+        mContext = context;
+
+        mPipBoundsState = pipBoundsState;
+        mPipBoundsState.setDisplayInfo(getDisplayInfo());
+        mPipBoundsAlgorithm = pipBoundsAlgorithm;
+
+        mPipMediaController = pipMediaController;
+
+        mPipNotificationController = pipNotificationController;
+        mPipNotificationController.setDelegate(this);
+
+        mTvPipMenuController = tvPipMenuController;
+        mTvPipMenuController.setDelegate(this);
+
+        mPipTaskOrganizer = pipTaskOrganizer;
+        mPipTaskOrganizer.registerPipTransitionCallback(this);
+
+        loadConfigurations();
+
+        registerTaskStackListenerCallback(taskStackListener);
+        registerWmShellPinnedStackListener(wmShell);
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        if (DEBUG) Log.d(TAG, "onConfigurationChanged(), state=" + stateToName(mState));
+
+        if (isPipShown()) {
+            if (DEBUG) Log.d(TAG, "  > closing Pip.");
+            closePip();
+        }
+
+        loadConfigurations();
+        mPipNotificationController.onConfigurationChanged(mContext);
+    }
+
+    /**
+     * Returns {@code true} if Pip is shown.
+     */
+    @Override
+    public boolean isPipShown() {
+        return mState != STATE_NO_PIP;
+    }
+
+    /**
+     * Starts the process if bringing up the Pip menu if by issuing a command to move Pip
+     * task/window to the "Menu" position. We'll show the actual Menu UI (eg. actions) once the Pip
+     * task/window is properly positioned in {@link #onPipTransitionFinished(ComponentName, int)}.
+     */
+    @Override
+    public void showPictureInPictureMenu() {
+        if (DEBUG) Log.d(TAG, "showPictureInPictureMenu(), state=" + stateToName(mState));
+
+        if (mState != STATE_PIP) {
+            if (DEBUG) Log.d(TAG, "  > cannot open Menu from the current state.");
+            return;
+        }
+
+        setState(STATE_PIP_MENU);
+        resizePinnedStack(STATE_PIP_MENU);
+    }
+
+    /**
+     * Moves Pip window to its "normal" position.
+     */
+    @Override
+    public void movePipToNormalPosition() {
+        if (DEBUG) Log.d(TAG, "movePipToNormalPosition(), state=" + stateToName(mState));
+
+        setState(STATE_PIP);
+        resizePinnedStack(STATE_PIP);
+    }
+
+    /**
+     * Opens the "Pip-ed" Activity fullscreen.
+     */
+    @Override
+    public void movePipToFullscreen() {
+        if (DEBUG) Log.d(TAG, "movePipToFullscreen(), state=" + stateToName(mState));
+
+        mPipTaskOrganizer.exitPip(mResizeAnimationDuration);
+        onPipDisappeared();
+    }
+
+    /**
+     * Closes Pip window.
+     */
+    @Override
+    public void closePip() {
+        if (DEBUG) Log.d(TAG, "closePip(), state=" + stateToName(mState));
+
+        removeTask(mPinnedTaskId);
+        onPipDisappeared();
+    }
+
+    /**
+     * Resizes the Pip task/window to the appropriate size for the given state.
+     * This is a legacy API. Now we expect that the state argument passed to it should always match
+     * the current state of the Controller. If it does not match an {@link IllegalArgumentException}
+     * will be thrown. However, if the passed state does match - we'll determine the right bounds
+     * to the state and will move Pip task/window there.
+     *
+     * @param state the to determine the Pip bounds. IMPORTANT: should always match the current
+     *              state of the Controller.
+     */
+    @Override
+    public void resizePinnedStack(@State int state) {
+        if (state != mState) {
+            throw new IllegalArgumentException("The passed state should match the current state!");
+        }
+        if (DEBUG) Log.d(TAG, "resizePinnedStack() state=" + stateToName(mState));
+
+        final Rect newBounds;
+        switch (mState) {
+            case STATE_PIP_MENU:
+                newBounds = mPipBoundsState.getExpandedBounds();
+                break;
+
+            case STATE_PIP:
+                // Let PipBoundsAlgorithm figure out what the correct bounds are at the moment.
+                // Internally, it will get the "default" bounds from PipBoundsState and adjust them
+                // as needed to account for things like IME state (will query PipBoundsState for
+                // this information as well, so it's important to keep PipBoundsState up to date).
+                newBounds = mPipBoundsAlgorithm.getNormalBounds();
+                break;
+
+            case STATE_NO_PIP:
+            default:
+                return;
+        }
+
+        mPipTaskOrganizer.scheduleAnimateResizePip(newBounds, mResizeAnimationDuration, null);
+    }
+
+    @Override
+    public void registerSessionListenerForCurrentUser() {
+        mPipMediaController.registerSessionListenerForCurrentUser();
+    }
+
+    private void checkIfPinnedTaskAppeared() {
+        final TaskInfo pinnedTask = getPinnedTaskInfo();
+        if (DEBUG) Log.d(TAG, "checkIfPinnedTaskAppeared(), task=" + pinnedTask);
+        if (pinnedTask == null) return;
+        mPinnedTaskId = pinnedTask.taskId;
+        setState(STATE_PIP);
+
+        mPipMediaController.onActivityPinned();
+        mPipNotificationController.show(pinnedTask.topActivity.getPackageName());
+    }
+
+    private void checkIfPinnedTaskIsGone() {
+        if (DEBUG) Log.d(TAG, "onTaskStackChanged()");
+
+        if (isPipShown() && getPinnedTaskInfo() == null) {
+            Log.w(TAG, "Pinned task is gone.");
+            onPipDisappeared();
+        }
+    }
+
+    private void onPipDisappeared() {
+        if (DEBUG) Log.d(TAG, "onPipDisappeared() state=" + stateToName(mState));
+
+        mPipNotificationController.dismiss();
+        mTvPipMenuController.hideMenu();
+        setState(STATE_NO_PIP);
+        mPinnedTaskId = NONEXISTENT_TASK_ID;
+    }
+
+    @Override
+    public void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds) {
+        if (DEBUG) Log.d(TAG, "onPipTransition_Started(), state=" + stateToName(mState));
+    }
+
+    @Override
+    public void onPipTransitionCanceled(ComponentName activity, int direction) {
+        if (DEBUG) Log.d(TAG, "onPipTransition_Canceled(), state=" + stateToName(mState));
+    }
+
+    @Override
+    public void onPipTransitionFinished(ComponentName activity, int direction) {
+        if (DEBUG) Log.d(TAG, "onPipTransition_Finished(), state=" + stateToName(mState));
+
+        if (mState == STATE_PIP_MENU) {
+            if (DEBUG) Log.d(TAG, "  > show menu");
+            mTvPipMenuController.showMenu();
+        }
+    }
+
+    private void setState(@State int state) {
+        if (DEBUG) {
+            Log.d(TAG, "setState(), state=" + stateToName(state) + ", prev="
+                    + stateToName(mState));
+        }
+        mState = state;
+    }
+
+    private void loadConfigurations() {
+        final Resources res = mContext.getResources();
+        mResizeAnimationDuration = res.getInteger(R.integer.config_pipResizeAnimationDuration);
+        // "Cache" bounds for the Pip menu as "expanded" bounds in PipBoundsState. We'll refer back
+        // to this value in resizePinnedStack(), when we are adjusting Pip task/window position for
+        // the menu.
+        mPipBoundsState.setExpandedBounds(
+                Rect.unflattenFromString(res.getString(R.string.pip_menu_bounds)));
+    }
+
+    private DisplayInfo getDisplayInfo() {
+        final DisplayInfo displayInfo = new DisplayInfo();
+        mContext.getDisplay().getDisplayInfo(displayInfo);
+        return displayInfo;
+    }
+
+    private void registerTaskStackListenerCallback(TaskStackListenerImpl taskStackListener) {
+        taskStackListener.addListener(new TaskStackListenerCallback() {
+            @Override
+            public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
+                checkIfPinnedTaskAppeared();
+            }
+
+            @Override
+            public void onTaskStackChanged() {
+                checkIfPinnedTaskIsGone();
+            }
+
+            @Override
+            public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+                    boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
+                if (task.getWindowingMode() == WINDOWING_MODE_PINNED) {
+                    if (DEBUG) Log.d(TAG, "onPinnedActivityRestartAttempt()");
+
+                    // If the "Pip-ed" Activity is launched again by Launcher or intent, make it
+                    // fullscreen.
+                    movePipToFullscreen();
+                }
+            }
+        });
+    }
+
+    private void registerWmShellPinnedStackListener(WindowManagerShellWrapper wmShell) {
+        try {
+            wmShell.addPinnedStackListener(new PinnedStackListenerForwarder.PinnedStackListener() {
+                @Override
+                public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
+                    if (DEBUG) {
+                        Log.d(TAG, "onImeVisibilityChanged(), visible=" + imeVisible
+                                + ", height=" + imeHeight);
+                    }
+
+                    if (imeVisible == mPipBoundsState.isImeShowing()
+                            && (!imeVisible || imeHeight == mPipBoundsState.getImeHeight())) {
+                        // Nothing changed: either IME has been and remains invisible, or remains
+                        // visible with the same height.
+                        return;
+                    }
+                    mPipBoundsState.setImeVisibility(imeVisible, imeHeight);
+                    // "Normal" Pip bounds may have changed, so if we are in the "normal" state,
+                    // let's update the bounds.
+                    if (mState == STATE_PIP) {
+                        resizePinnedStack(STATE_PIP);
+                    }
+                }
+
+                @Override
+                public void onMovementBoundsChanged(boolean fromImeAdjustment) {}
+
+                @Override
+                public void onActionsChanged(ParceledListSlice<RemoteAction> actions) {
+                    if (DEBUG) Log.d(TAG, "onActionsChanged()");
+
+                    mTvPipMenuController.setAppActions(actions);
+                }
+            });
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to register pinned stack listener", e);
+        }
+    }
+
+    private static TaskInfo getPinnedTaskInfo() {
+        if (DEBUG) Log.d(TAG, "getPinnedTaskInfo()");
+        try {
+            final TaskInfo taskInfo = ActivityTaskManager.getService().getRootTaskInfo(
+                    WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
+            if (DEBUG) Log.d(TAG, "  > taskInfo=" + taskInfo);
+            return taskInfo;
+        } catch (RemoteException e) {
+            Log.e(TAG, "getRootTaskInfo() failed", e);
+            return null;
+        }
+    }
+
+    private static void removeTask(int taskId) {
+        if (DEBUG) Log.d(TAG, "removeTask(), taskId=" + taskId);
+        try {
+            ActivityTaskManager.getService().removeTask(taskId);
+        } catch (Exception e) {
+            Log.e(TAG, "Atm.removeTask() failed", e);
+        }
+    }
+
+    private static String stateToName(@State int state) {
+        switch (state) {
+            case STATE_NO_PIP:
+                return "NO_PIP";
+            case STATE_PIP:
+                return "PIP";
+            case STATE_PIP_MENU:
+                return "PIP_MENU";
+            default:
+                // This can't happen.
+                throw new IllegalArgumentException("Unknown state " + state);
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
index 9192cf1..470ab0c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
@@ -42,7 +42,7 @@
  */
 public class TvPipMenuController implements PipMenuController, TvPipMenuView.Listener {
     private static final String TAG = "TvPipMenuController";
-    private static final boolean DEBUG = PipController.DEBUG;
+    private static final boolean DEBUG = TvPipController.DEBUG;
 
     private final Context mContext;
     private final SystemWindows mSystemWindows;
@@ -134,10 +134,18 @@
     }
 
     void hideMenu() {
-        if (DEBUG) Log.d(TAG, "hideMenu()");
+        hideMenu(true);
+    }
 
-        if (isMenuVisible()) {
-            mMenuView.hide();
+    void hideMenu(boolean movePipWindow) {
+        if (DEBUG) Log.d(TAG, "hideMenu(), movePipWindow=" + movePipWindow);
+
+        if (!isMenuVisible()) {
+            return;
+        }
+
+        mMenuView.hide();
+        if (movePipWindow) {
             mDelegate.movePipToNormalPosition();
         }
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
index f7b76c1..e08ca52 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
@@ -53,7 +53,7 @@
  */
 public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
     private static final String TAG = "TvPipMenuView";
-    private static final boolean DEBUG = PipController.DEBUG;
+    private static final boolean DEBUG = TvPipController.DEBUG;
 
     private static final float DISABLED_ACTION_ALPHA = 0.54f;
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java
similarity index 62%
rename from libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java
index 5716c7f..ce4b608 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java
@@ -19,14 +19,17 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.media.MediaMetadata;
+import android.os.UserHandle;
 import android.text.TextUtils;
+import android.util.Log;
 
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.wm.shell.R;
@@ -39,22 +42,27 @@
  * <p>Once it's created, it will manage the PIP notification UI by itself except for handling
  * configuration changes.
  */
-public class PipNotification {
-    private static final boolean DEBUG = PipController.DEBUG;
-    private static final String TAG = "PipNotification";
+public class TvPipNotificationController {
+    private static final String TAG = "TvPipNotification";
+    private static final boolean DEBUG = TvPipController.DEBUG;
 
-    private static final String NOTIFICATION_TAG = PipNotification.class.getSimpleName();
-    public static final String NOTIFICATION_CHANNEL_TVPIP = "TPP";
+    // Referenced in com.android.systemui.util.NotificationChannels.
+    public static final String NOTIFICATION_CHANNEL = "TVPIP";
+    private static final String NOTIFICATION_TAG = "TvPip";
 
-    static final String ACTION_MENU = "PipNotification.menu";
-    static final String ACTION_CLOSE = "PipNotification.close";
+    private static final String ACTION_SHOW_PIP_MENU =
+            "com.android.wm.shell.pip.tv.notification.action.SHOW_PIP_MENU";
+    private static final String ACTION_CLOSE_PIP =
+            "com.android.wm.shell.pip.tv.notification.action.CLOSE_PIP";
 
+    private final Context mContext;
     private final PackageManager mPackageManager;
     private final NotificationManager mNotificationManager;
     private final Notification.Builder mNotificationBuilder;
+    private final ActionBroadcastReceiver mActionBroadcastReceiver;
+    private Delegate mDelegate;
 
     private String mDefaultTitle;
-    private int mDefaultIconResId;
 
     /** Package name for the application that owns PiP window. */
     private String mPackageName;
@@ -62,32 +70,56 @@
     private String mMediaTitle;
     private Bitmap mArt;
 
-    public PipNotification(Context context, PipMediaController pipMediaController) {
+    public TvPipNotificationController(Context context, PipMediaController pipMediaController) {
+        mContext = context;
         mPackageManager = context.getPackageManager();
         mNotificationManager = context.getSystemService(NotificationManager.class);
 
-        mNotificationBuilder = new Notification.Builder(context, NOTIFICATION_CHANNEL_TVPIP)
+        mNotificationBuilder = new Notification.Builder(context, NOTIFICATION_CHANNEL)
                 .setLocalOnly(true)
                 .setOngoing(false)
                 .setCategory(Notification.CATEGORY_SYSTEM)
+                .setShowWhen(true)
+                .setSmallIcon(R.drawable.pip_icon)
                 .extend(new Notification.TvExtender()
-                        .setContentIntent(createPendingIntent(context, ACTION_MENU))
-                        .setDeleteIntent(createPendingIntent(context, ACTION_CLOSE)));
+                        .setContentIntent(createPendingIntent(context, ACTION_SHOW_PIP_MENU))
+                        .setDeleteIntent(createPendingIntent(context, ACTION_CLOSE_PIP)));
+
+        mActionBroadcastReceiver = new ActionBroadcastReceiver();
 
         pipMediaController.addMetadataListener(this::onMediaMetadataChanged);
 
         onConfigurationChanged(context);
     }
 
+    void setDelegate(Delegate delegate) {
+        if (DEBUG) Log.d(TAG, "setDelegate(), delegate=" + delegate);
+        if (mDelegate != null) {
+            throw new IllegalStateException(
+                    "The delegate has already been set and should not change.");
+        }
+        if (delegate == null) {
+            throw new IllegalArgumentException("The delegate must not be null.");
+        }
+
+        mDelegate = delegate;
+    }
+
     void show(String packageName) {
+        if (mDelegate == null) {
+            throw new IllegalStateException("Delegate is not set.");
+        }
+
         mPackageName = packageName;
         update();
+        mActionBroadcastReceiver.register();
     }
 
     void dismiss() {
         mNotificationManager.cancel(NOTIFICATION_TAG, SystemMessage.NOTE_TV_PIP);
         mNotified = false;
         mPackageName = null;
+        mActionBroadcastReceiver.unregister();
     }
 
     private void onMediaMetadataChanged(MediaMetadata metadata) {
@@ -101,11 +133,9 @@
      * Called by {@link PipController} when the configuration is changed.
      */
     void onConfigurationChanged(Context context) {
-        Resources res = context.getResources();
-        mDefaultTitle = res.getString(R.string.pip_notification_unknown_title);
-        mDefaultIconResId = R.drawable.pip_icon;
+        mDefaultTitle = context.getResources().getString(R.string.pip_notification_unknown_title);
         if (mNotified) {
-            // update notification
+            // Update the notification.
             update();
         }
     }
@@ -113,9 +143,7 @@
     private void update() {
         mNotified = true;
         mNotificationBuilder
-                .setShowWhen(true)
                 .setWhen(System.currentTimeMillis())
-                .setSmallIcon(mDefaultIconResId)
                 .setContentTitle(getNotificationTitle());
         if (mArt != null) {
             mNotificationBuilder.setStyle(new Notification.BigPictureStyle()
@@ -178,4 +206,45 @@
         return PendingIntent.getBroadcast(context, 0, new Intent(action),
                 PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
     }
+
+    private class ActionBroadcastReceiver extends BroadcastReceiver {
+        final IntentFilter mIntentFilter;
+        {
+            mIntentFilter = new IntentFilter();
+            mIntentFilter.addAction(ACTION_CLOSE_PIP);
+            mIntentFilter.addAction(ACTION_SHOW_PIP_MENU);
+        }
+        boolean mRegistered = false;
+
+        void register() {
+            if (mRegistered) return;
+
+            mContext.registerReceiver(this, mIntentFilter, UserHandle.USER_ALL);
+            mRegistered = true;
+        }
+
+        void unregister() {
+            if (!mRegistered) return;
+
+            mContext.unregisterReceiver(this);
+            mRegistered = false;
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            if (DEBUG) Log.d(TAG, "on(Broadcast)Receive(), action=" + action);
+
+            if (ACTION_SHOW_PIP_MENU.equals(action)) {
+                mDelegate.showPictureInPictureMenu();
+            } else if (ACTION_CLOSE_PIP.equals(action)) {
+                mDelegate.closePip();
+            }
+        }
+    }
+
+    interface Delegate {
+        void showPictureInPictureMenu();
+        void closePip();
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
similarity index 98%
rename from libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index 5213f6c..7ce71b0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.wm.shell;
+package com.android.wm.shell.transition;
 
 import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_CLOSE;
@@ -42,6 +42,7 @@
 import androidx.annotation.BinderThread;
 
 import com.android.internal.protolog.common.ProtoLog;
+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.protolog.ShellProtoLogGroup;
@@ -82,6 +83,7 @@
         mPlayerImpl = new TransitionPlayerImpl();
     }
 
+    /** Register this transition handler with Core */
     public void register(ShellTaskOrganizer taskOrganizer) {
         taskOrganizer.registerTransitionPlayer(mPlayerImpl);
     }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt
index 75388bf..5258e90 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt
@@ -171,4 +171,4 @@
     get() = tvExtensions?.getParcelable("delete_intent")
 
 private fun StatusBarNotification.isPipNotificationWithTitle(expectedTitle: String): Boolean =
-    tag == "PipNotification" && title == expectedTitle
\ No newline at end of file
+    tag == "TvPip" && title == expectedTitle
\ No newline at end of file
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 602364e..a4abf36 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -196,8 +196,9 @@
 static int IP_V4_LENGTH = 4;
 static int IP_V6_LENGTH = 16;
 
-void DestroyCallback(const C2Buffer * /* buf */, void *arg) {
+void DestroyCallback(const C2Buffer * buf, void *arg) {
     android::sp<android::MediaEvent> event = (android::MediaEvent *)arg;
+    android::Mutex::Autolock autoLock(event->mLock);
     if (event->mLinearBlockObj != NULL) {
         JNIEnv *env = android::AndroidRuntime::getJNIEnv();
         env->DeleteWeakGlobalRef(event->mLinearBlockObj);
@@ -206,6 +207,7 @@
 
     event->mAvHandleRefCnt--;
     event->finalize();
+    event->decStrong(buf);
 }
 
 namespace android {
@@ -408,6 +410,7 @@
             pC2Buffer->setInfo(info);
         }
         pC2Buffer->registerOnDestroyNotify(&DestroyCallback, this);
+        incStrong(pC2Buffer.get());
         jobject linearBlock =
                 env->NewObject(
                         env->FindClass("android/media/MediaCodec$LinearBlock"),
@@ -4411,6 +4414,7 @@
         ALOGD("Failed get MediaEvent");
         return NULL;
     }
+    android::Mutex::Autolock autoLock(mediaEventSp->mLock);
 
     return mediaEventSp->getLinearBlock();
 }
diff --git a/packages/Connectivity/service/Android.bp b/packages/Connectivity/service/Android.bp
index a26f715..c8f3bd3 100644
--- a/packages/Connectivity/service/Android.bp
+++ b/packages/Connectivity/service/Android.bp
@@ -14,8 +14,8 @@
 // limitations under the License.
 //
 
-cc_defaults {
-    name: "libservice-connectivity-defaults",
+cc_library_shared {
+    name: "libservice-connectivity",
     // TODO: build against the NDK (sdk_version: "30" for example)
     cflags: [
         "-Wall",
@@ -26,6 +26,7 @@
     srcs: [
         "jni/com_android_server_TestNetworkService.cpp",
         "jni/com_android_server_connectivity_Vpn.cpp",
+        "jni/onload.cpp",
     ],
     shared_libs: [
         "libbase",
@@ -35,27 +36,11 @@
         // addresses, and remove dependency on libnetutils.
         "libnetutils",
     ],
-}
-
-cc_library_shared {
-    name: "libservice-connectivity",
-    defaults: ["libservice-connectivity-defaults"],
-    srcs: [
-        "jni/onload.cpp",
-    ],
     apex_available: [
-        // TODO: move this library to the tethering APEX and remove libservice-connectivity-static
-        // "com.android.tethering",
+        "com.android.tethering",
     ],
 }
 
-// Static library linked into libservices.core until libservice-connectivity can be loaded from
-// the tethering APEX instead.
-cc_library_static {
-    name: "libservice-connectivity-static",
-    defaults: ["libservice-connectivity-defaults"],
-}
-
 java_library {
     name: "service-connectivity",
     srcs: [
@@ -75,5 +60,6 @@
     ],
     apex_available: [
         "//apex_available:platform",
+        "com.android.tethering",
     ],
 }
diff --git a/packages/PrintSpooler/res/values-or/strings.xml b/packages/PrintSpooler/res/values-or/strings.xml
index 7000b95..15cecd6 100644
--- a/packages/PrintSpooler/res/values-or/strings.xml
+++ b/packages/PrintSpooler/res/values-or/strings.xml
@@ -80,10 +80,10 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g>ଟି ପ୍ରିଣ୍ଟର୍‍ ଖୋଜିବା ପାଇଁ ଇନଷ୍ଟଲ୍‍ କରନ୍ତୁ</item>
     </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ପ୍ରିଣ୍ଟ କରାଯାଉଛି"</string>
-    <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> କ୍ୟାନ୍ସଲ୍‍ କରାଯାଉଛି"</string>
+    <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ବାତିଲ୍‍ କରାଯାଉଛି"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ପ୍ରିଣ୍ଟର୍‍ ତ୍ରୁଟି"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"ପ୍ରିଣ୍ଟର୍‍ ଦ୍ୱାରା ରୋକାଯାଇଥିବା <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <string name="cancel" msgid="4373674107267141885">"କ୍ୟାନ୍ସଲ୍‍"</string>
+    <string name="cancel" msgid="4373674107267141885">"ବାତିଲ୍‍"</string>
     <string name="restart" msgid="2472034227037808749">"ରିଷ୍ଟାର୍ଟ କରନ୍ତୁ"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"ପ୍ରିଣ୍ଟର୍‍କୁ କୌଣସି ସଂଯୋଗ ନାହିଁ"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"ଅଜଣା"</string>
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index c1c1d65..e22f264 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -217,6 +217,7 @@
                     Settings.Global.DEBUG_APP,
                     Settings.Global.DEBUG_VIEW_ATTRIBUTES,
                     Settings.Global.DEBUG_VIEW_ATTRIBUTES_APPLICATION_PACKAGE,
+                    Settings.Global.DECORATED_CUSTOM_VIEW_NOTIF_DECORATION,
                     Settings.Global.DEFAULT_DNS_SERVER,
                     Settings.Global.DEFAULT_INSTALL_LOCATION,
                     Settings.Global.DEFAULT_RESTRICT_BACKGROUND_DATA,
@@ -285,6 +286,7 @@
                     Settings.Global.WIFI_ON_WHEN_PROXY_DISCONNECTED,
                     Settings.Global.FSTRIM_MANDATORY_INTERVAL,
                     Settings.Global.FOREGROUND_SERVICE_STARTS_LOGGING_ENABLED,
+                    Settings.Global.FULLY_CUSTOM_VIEW_NOTIF_DECORATION,
                     Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
                     Settings.Global.GLOBAL_HTTP_PROXY_HOST,
                     Settings.Global.GLOBAL_HTTP_PROXY_PAC,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 0a43014..14151191 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -379,6 +379,9 @@
     <uses-permission android:name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS" />
     <uses-permission android:name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" />
 
+    <!-- Permission required for CTS tests to enable/disable rate limiting toasts. -->
+    <uses-permission android:name="android.permission.MANAGE_TOAST_RATE_LIMITING" />
+
     <application android:label="@string/app_label"
                 android:theme="@android:style/Theme.DeviceDefault.DayNight"
                 android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
index 19f8248..55bdebd 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
@@ -89,7 +89,6 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_below="@id/keyguard_status_area"
-        android:paddingTop="20dp"
         android:visibility="gone">
         <com.android.keyguard.AnimatableClockView
             android:id="@+id/animatable_clock_view_large"
@@ -97,7 +96,7 @@
             android:layout_height="wrap_content"
             android:layout_gravity="center_horizontal"
             android:gravity="center_horizontal"
-            android:textSize="200dp"
+            android:textSize="@dimen/large_clock_text_size"
             android:letterSpacing="0.02"
             android:lineSpacingMultiplier=".8"
             android:includeFontPadding="false"
diff --git a/packages/SystemUI/res-keyguard/values-ml/strings.xml b/packages/SystemUI/res-keyguard/values-ml/strings.xml
index 66d0ac7..8076159 100644
--- a/packages/SystemUI/res-keyguard/values-ml/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ml/strings.xml
@@ -38,7 +38,7 @@
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ചാർജ് ചെയ്യുന്നു"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • വേഗത്തിൽ ചാർജ് ചെയ്യുന്നു"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • പതുക്കെ ചാർജ് ചെയ്യുന്നു"</string>
-    <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ബാറ്ററി നില ഒപ്റ്റിമൈസ് ചെയ്യുന്നു"</string>
+    <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ബാറ്ററിയുടെ ആയുസിനായി ഒപ്റ്റിമൈസ് ചെയ്യുന്നു"</string>
     <string name="keyguard_low_battery" msgid="1868012396800230904">"നിങ്ങളുടെ ചാർജർ കണക്റ്റുചെയ്യുക."</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"അൺലോക്കുചെയ്യാൻ മെനു അമർത്തുക."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"നെറ്റ്‌വർക്ക് ലോക്കുചെയ്‌തു"</string>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index fe4ba63..0beb286 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Gebruiker"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nuwe gebruiker"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nie gekoppel nie"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Geen netwerk nie"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi af"</string>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Wys profiel"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Voeg gebruiker by"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Nuwe gebruiker"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Beëindig gastesessie?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle programme en data in hierdie sessie sal uitgevee word."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Beëindig sessie"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Welkom terug, gas!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Wiil jy jou sessie voortsit?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Begin van voor af"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 9149aa6..f56e84a 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"ተጠቃሚ"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"አዲስ ተጠቃሚ"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"በይነመረብ"</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>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"መገለጫ አሳይ"</string>
     <string name="user_add_user" msgid="4336657383006913022">"ተጠቃሚ አክል"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"አዲስ ተጠቃሚ"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"የእንግዳ ክፍለ-ጊዜ ይብቃ?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"በዚህ ክፍለ-ጊዜ ውስጥ ያሉ ሁሉም መተግበሪያዎች እና ውሂብ ይሰረዛሉ።"</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"ክፍለ-ጊዜን አብቃ"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"እንኳን በደህና ተመለሱ እንግዳ!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"ክፍለ-ጊዜዎን መቀጠል ይፈልጋሉ?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"እንደገና ጀምር"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 0146fcd..aaaf778 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -357,8 +357,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"المستخدم"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"مستخدم جديد"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"الإنترنت"</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>
@@ -464,11 +463,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"عرض الملف الشخصي"</string>
     <string name="user_add_user" msgid="4336657383006913022">"إضافة مستخدم"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"مستخدم جديد"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"هل تريد إنهاء جلسة الضيف؟"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"سيتم حذف كل التطبيقات والبيانات في هذه الجلسة."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"إنهاء الجلسة"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"مرحبًا بك مجددًا في جلسة الضيف"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"هل تريد متابعة جلستك؟"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"البدء من جديد"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 3c206f2..7e3e3cb 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -456,11 +456,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"প্ৰ\'ফাইল দেখুৱাওক"</string>
     <string name="user_add_user" msgid="4336657383006913022">"ব্যৱহাৰকাৰী যোগ কৰক"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"নতুন ব্যৱহাৰকাৰী"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"অতিথিৰ ছেশ্বন সমাপ্ত কৰিবনে?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"এই ছেশ্বনৰ সকলো এপ্ আৰু ডেটা মচা হ\'ব।"</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"ছেশ্বন সমাপ্ত কৰক"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"আপোনাক পুনৰাই স্বাগতম জনাইছোঁ!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"আপুনি আপোনাৰ ছেশ্বন অব্যাহত ৰাখিব বিচাৰেনে?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"আকৌ আৰম্ভ কৰক"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 67e1718..6c22cc3 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"İstifadəçi"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Yeni istifadəçi"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"İnternet"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Bağlantı yoxdur"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Şəbəkə yoxdur"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi sönülüdür"</string>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Show profile"</string>
     <string name="user_add_user" msgid="4336657383006913022">"İstifadəçi əlavə edin"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Yeni istifadəçi"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Qonaq sessiyası bitirilsin?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bu sessiyada bütün tətbiqlər və data silinəcək."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Sessiyanı bitirin"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Xoş gəlmisiniz!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Sessiya davam etsin?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Yenidən başlayın"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index ae8ffbf..2f3d6d2 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -354,8 +354,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Korisnik"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Novi korisnik"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"WiFi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Veza nije uspostavljena"</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>
@@ -458,11 +457,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Prikaži profil"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Dodaj korisnika"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Novi korisnik"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Želite da završite sesiju gosta?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci u ovoj sesiji će biti izbrisani."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Završi sesiju"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Dobro došli nazad, goste!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite li da nastavite sesiju?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Počni iz početka"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index b90d57e..925e86a 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -355,8 +355,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Карыстальнік"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Новы карыстальнік"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Інтэрнэт"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Няма падключэння"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Няма сеткi"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi адключаны"</string>
@@ -460,11 +459,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Паказаць профіль"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Дадаць карыстальніка"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Новы карыстальнік"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Завяршыць гасцявы сеанс?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Усе праграмы і даныя гэтага сеанса будуць выдалены."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Завяршыць сеанс"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"З вяртаннем, госць!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Хочаце працягнуць сеанс?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Пачаць зноў"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index bfc8ef1..6a683c7 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Потребител"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Нов потребител"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Интернет"</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>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Показване на потребителския профил"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Добавяне на потребител"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Нов потребител"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Да се прекрати ли сесията като гост?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Всички приложения и данни в тази сесия ще бъдат изтрити."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Прекратяване на сесията"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Добре дошли отново в сесията като гост!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Искате ли да продължите сесията си?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Започване отначало"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index c41a434..953ec00 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"ব্যবহারকারী"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"নতুন ব্যবহারকারী"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"ওয়াই-ফাই"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"ইন্টারনেট"</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>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"প্রোফাইল দেখান"</string>
     <string name="user_add_user" msgid="4336657383006913022">"ব্যবহারকারী জুড়ুন"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"নতুন ব্যবহারকারী"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"গেস্ট সেশন শেষ করতে চান?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"এই সেশনের সব অ্যাপ্লিকেশান ও ডেটা মুছে ফেলা হবে।"</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"সেশন শেষ করুন"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"অতিথি, আপনি ফিরে আসায় আপনাকে স্বাগত!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"আপনি কি আপনার সেশনটি অবিরত রাখতে চান?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"আবার শুরু করুন"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 9a28773..6bf1852 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -354,8 +354,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Korisnik"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Novi korisnik"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"WiFi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</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>
@@ -458,11 +457,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Pokaži profil"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Dodaj korisnika"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Novi korisnik"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Završiti sesiju gosta?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i svi podaci iz ove sesije bit će izbrisani."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Završi sesiju"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Zdravo! Lijepo je opet vidjeti goste."</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite li nastaviti sesiju?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Počni ispočetka"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 426005a..71105cc 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Usuari"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Usuari nou"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Desconnectat"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"No hi ha cap xarxa"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi desconnectada"</string>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Mostra el perfil"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Afegeix un usuari"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Usuari nou"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Vols finalitzar la sessió de convidat?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Totes les aplicacions i les dades d\'aquesta sessió se suprimiran."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Finalitza la sessió"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Benvingut de nou, convidat."</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vols continuar amb la sessió?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Torna a començar"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 3e015ec..65e6767 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -355,8 +355,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Uživatel"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nový uživatel"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nepřipojeno"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Žádná síť"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi vypnuta"</string>
@@ -460,11 +459,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Zobrazit profil"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Přidat uživatele"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Nový uživatel"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Ukončit relaci hosta?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Veškeré aplikace a data v této relaci budou vymazána."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Ukončit relaci"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Vítejte zpět v relaci hosta!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Chcete v relaci pokračovat?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Začít znovu"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 8fd48b1..e50aa57 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Bruger"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Ny bruger"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Ikke forbundet"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Intet netværk"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi slået fra"</string>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Vis profil"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Tilføj bruger"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Ny bruger"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Vil du afslutte gæstesessionen?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apps og data i denne session slettes."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Afslut sessionen"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Velkommen tilbage, gæst!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vil du fortsætte din session?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start forfra"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 84b63ba..3cdebf9 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Nutzer"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Neuer Nutzer"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"WLAN"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nicht verbunden"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Kein Netz"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"WLAN aus"</string>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Profil öffnen"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Nutzer hinzufügen"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Neuer Nutzer"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Gastsitzung beenden?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle Apps und Daten in dieser Sitzung werden gelöscht."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Sitzung beenden"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Willkommen zurück im Gastmodus"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Möchtest du deine Sitzung fortsetzen?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Neu starten"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index bec78c0..c6ae7f4 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Χρήστης"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Νέος χρήστης"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Διαδίκτυο"</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>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Εμφάνιση προφίλ"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Προσθήκη χρήστη"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Νέος χρήστης"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Λήξη περιόδου σύνδεσης επισκέπτη;"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Όλες οι εφαρμογές και τα δεδομένα αυτής της περιόδου σύνδεσης θα διαγραφούν."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Λήξη περιόδου σύνδεσης"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Επισκέπτη , καλώς όρισες ξανά!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Θέλετε να συνεχίσετε την περίοδο σύνδεσής σας;"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Έναρξη από την αρχή"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 21cac18..ea25ec6 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"User"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"New user"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</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-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 7ac4c0d..a373a5c 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"User"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"New user"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</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-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 21cac18..ea25ec6 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"User"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"New user"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</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-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 21cac18..ea25ec6 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"User"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"New user"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</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-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 2f30c41..101d112 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‏‏‎‎‏‏‎‏‏‎‎‏‎‏‎‏‏‎‏‎‏‏‏‏‏‏‎‎‏‎‎‎‏‏‏‎‎‏‎‏‏‎‏‎‏‏‏‏‏‎‎‏‎User‎‏‎‎‏‎"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‎‎‏‏‏‎‏‏‎‎‎‏‎‎‏‏‎‏‎‏‎‎‏‏‎‏‏‏‎‏‎‏‎‎‏‏‎‏‏‏‎‎‏‎‏‏‎‏‎‎‎‏‎‎‎‏‎‎New user‎‏‎‎‏‎"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‎‎‎‏‏‎‏‏‎‎‎‎‏‎‎‏‏‏‏‏‎‎‎‏‎‏‎‏‏‎‎‏‎‏‏‎‎‎‎‏‏‎‎‎Wi-Fi‎‏‎‎‏‎"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‎‎‏‎‏‏‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‏‏‏‎‏‎‎‎‏‎‏‎‏‎‎‎‏‎‎‏‎‏‏‎‎‏‎‎‏‏‏‎Internet‎‏‎‎‏‎"</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 7ef9cdb..1fc1609 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Usuario"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Usuario nuevo"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Sin conexión"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Sin red"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi desactivada"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 6c6b511..dd36a64 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Usuario"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nuevo usuario"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"No conectado"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"No hay red."</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi desactivado"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index c64a07e..fb27be9 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Kasutaja"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Uus kasutaja"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"WiFi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Ühendus puudub"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Võrku pole"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"WiFi-ühendus on väljas"</string>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Kuva profiil"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Lisa kasutaja"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Uus kasutaja"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Kas lõpetada külastajaseanss?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Seansi kõik rakendused ja andmed kustutatakse."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Lõpeta seanss"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Tere tulemast tagasi, külaline!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Kas soovite seansiga jätkata?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Alusta uuesti"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 5047cf1..d8b21c6 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Erabiltzailea"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Erabiltzaile berria"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wifia"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Konektatu gabe"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ez dago sarerik"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi konexioa desaktibatuta"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 34c6bf6..df306f8 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"کاربر"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"کاربر جدید"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"اینترنت"</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>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"نمایش نمایه"</string>
     <string name="user_add_user" msgid="4336657383006913022">"افزودن کاربر"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"کاربر جدید"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"جلسه مهمان تمام شود؟"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"همه برنامه‌ها و داده‌های این جلسه حذف خواهد شد."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"پایان جلسه"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"مهمان گرامی، بازگشتتان را خوش آمد می‌گوییم!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"آیا می‌خواهید جلسه‌تان را ادامه دهید؟"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"شروع مجدد"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 5486e39..4e0af37 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Käyttäjä"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Uusi käyttäjä"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Ei yhteyttä"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ei verkkoa"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi-yhteys pois käytöstä"</string>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Näytä profiili"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Lisää käyttäjä"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Uusi käyttäjä"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Lopetetaanko Vierailija-käyttökerta?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Kaikki sovellukset ja tämän istunnon tiedot poistetaan."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Lopeta käyttökerta"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Tervetuloa takaisin!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Haluatko jatkaa istuntoa?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Aloita alusta"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 63f65e0..8c944a4 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Utilisateur"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nouvel utilisateur"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</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>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Afficher le profil"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Ajouter un utilisateur"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Nouvel utilisateur"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Mettre fin à la session d\'invité?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applications et les données de cette session seront supprimées."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Fermer la session"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Bienvenue à nouveau dans la session Invité"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Voulez-vous poursuivre la session?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recommencer"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index ebf199bf..7ad239d 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Utilisateur"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nouvel utilisateur"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</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>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Afficher le profil"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Ajouter un utilisateur"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Nouvel utilisateur"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Fermer la session Invité ?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applications et les données de cette session seront supprimées."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Fermer la session"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Bienvenue à nouveau dans la session Invité"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Voulez-vous poursuivre la dernière session ?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Non, nouvelle session"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 36f7f4c..145b3c0 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Usuario"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Novo usuario"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wifi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Non conectada"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Non hai rede"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wifi desactivada"</string>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Mostrar perfil"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Engadir usuario"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Novo usuario"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Queres finalizar a sesión de invitado?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Eliminaranse todas as aplicacións e datos desta sesión."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Finalizar sesión"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Benvido de novo, convidado."</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Queres continuar coa túa sesión?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Comezar de novo"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 66423e4..ea7af17 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"વપરાશકર્તા"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"નવો વપરાશકર્તા"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"વાઇ-ફાઇ"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"ઇન્ટરનેટ"</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>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"પ્રોફાઇલ બતાવો"</string>
     <string name="user_add_user" msgid="4336657383006913022">"વપરાશકર્તા ઉમેરો"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"નવો વપરાશકર્તા"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"શું અતિથિ સત્ર સમાપ્ત કરીએ?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"આ સત્રમાંની તમામ ઍપ્લિકેશનો અને ડેટા કાઢી નાખવામાં આવશે."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"સત્ર સમાપ્ત કરો"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"ફરી સ્વાગત છે, અતિથિ!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"શું તમે તમારું સત્ર ચાલુ કરવા માંગો છો?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"શરૂ કરો"</string>
diff --git a/packages/SystemUI/res/values-h700dp/dimens.xml b/packages/SystemUI/res/values-h700dp/dimens.xml
new file mode 100644
index 0000000..fbd985e
--- /dev/null
+++ b/packages/SystemUI/res/values-h700dp/dimens.xml
@@ -0,0 +1,20 @@
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<resources>
+    <!-- Large clock maximum font size (dp is intentional, to prevent any further scaling) -->
+    <dimen name="large_clock_text_size">170dp</dimen>
+</resources>
diff --git a/packages/SystemUI/res/values-h800dp/dimens.xml b/packages/SystemUI/res/values-h800dp/dimens.xml
index 6a0e880..cfacbec 100644
--- a/packages/SystemUI/res/values-h800dp/dimens.xml
+++ b/packages/SystemUI/res/values-h800dp/dimens.xml
@@ -17,4 +17,7 @@
 <resources>
     <!-- Minimum margin between clock and top of screen or ambient indication -->
     <dimen name="keyguard_clock_top_margin">76dp</dimen>
-</resources>
\ No newline at end of file
+
+    <!-- Large clock maximum font size (dp is intentional, to prevent any further scaling) -->
+    <dimen name="large_clock_text_size">200dp</dimen>
+</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 65cba2f..a8bed5b 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -355,8 +355,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"उपयोगकर्ता"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"नया उपयोगकर्ता"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"वाई-फ़ाई"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"इंटरनेट"</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>
@@ -458,11 +457,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"प्रोफ़ाइल दिखाएं"</string>
     <string name="user_add_user" msgid="4336657383006913022">"उपयोगकर्ता जोड़ें"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"नया उपयोगकर्ता"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"मेहमान के तौर पर ब्राउज़ करने का सेशन खत्म करना चाहते हैं?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"इस सत्र के सभी ऐप्स और डेटा को हटा दिया जाएगा."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"सेशन खत्म करें"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"अतिथि, आपका फिर से स्वागत है!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"क्‍या आप अपना सत्र जारी रखना चाहते हैं?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"फिर से शुरू करें"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 7d60619..4ffa5b2 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -354,8 +354,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Korisnik"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Novi korisnik"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</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>
@@ -458,11 +457,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Prikaz profila"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Dodavanje korisnika"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Novi korisnik"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Završiti gostujuću sesiju?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci u ovoj sesiji bit će izbrisani."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Završi sesiju"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Dobro došli natrag, gostu!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite li nastaviti sesiju?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Počni ispočetka"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 2ee8913..cff5b0d 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Felhasználó"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Új felhasználó"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nincs kapcsolat"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Nincs hálózat"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi kikapcsolva"</string>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Profil megjelenítése"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Felhasználó hozzáadása"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Új felhasználó"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Befejezi a vendég munkamenetet?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"A munkamenetben található összes alkalmazás és adat törlődni fog."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Munkamenet befejezése"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Örülünk, hogy visszatért, vendég!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Folytatja a munkamenetet?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Újrakezdés"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 18af1ea..91ffe73 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Օգտատեր"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Նոր օգտատեր"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Ինտերնետ"</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 4a048bb..f9e7397 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Pengguna"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Pengguna baru"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Tidak Terhubung"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Tidak Ada Jaringan"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi Mati"</string>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Tampilkan profil"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Tambahkan pengguna"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Pengguna baru"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Akhiri sesi tamu?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Semua aplikasi dan data di sesi ini akan dihapus."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Akhiri sesi"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Selamat datang kembali, tamu!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Lanjutkan sesi Anda?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Mulai ulang"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 10e11fc..db5dac43 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Notandi"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nýr notandi"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Engin tenging"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ekkert net"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Slökkt á Wi-Fi"</string>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Sýna snið"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Bæta notanda við"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Nýr notandi"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Ljúka gestalotu?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Öllum forritum og gögnum í þessari lotu verður eytt."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Ljúka lotu"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Velkominn aftur, gestur!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Viltu halda áfram með lotuna?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Byrja upp á nýtt"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 24e3f47..86e65bb 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -63,7 +63,7 @@
     <string name="usb_debugging_allow" msgid="1722643858015321328">"Consenti"</string>
     <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Debug USB non consentito"</string>
     <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"L\'utente che ha eseguito l\'accesso a questo dispositivo non può attivare il debug USB. Per utilizzare questa funzione, passa all\'utente principale."</string>
-    <string name="wifi_debugging_title" msgid="7300007687492186076">"Consentire debug wireless su questa rete?"</string>
+    <string name="wifi_debugging_title" msgid="7300007687492186076">"Consentire il debug wireless su questa rete?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Nome della rete (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nIndirizzo Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Consenti sempre su questa rete"</string>
     <string name="wifi_debugging_allow" msgid="4573224609684957886">"Consenti"</string>
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Utente"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nuovo utente"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Non connessa"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Nessuna rete"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi disattivato"</string>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Mostra profilo"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Aggiungi utente"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Nuovo utente"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Vuoi terminare la sessione Ospite?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tutte le app e i dati di questa sessione verranno eliminati."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Termina sessione"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Bentornato, ospite."</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vuoi continuare la sessione?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Ricomincia"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 76dbdf9..8548dae 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -355,8 +355,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"משתמש"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"משתמש חדש"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"אינטרנט"</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>
@@ -460,11 +459,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"הצג פרופיל"</string>
     <string name="user_add_user" msgid="4336657383006913022">"הוספת משתמש"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"משתמש חדש"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"להפסיק את הגלישה כאורח?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"כל האפליקציות והנתונים בפעילות זו באתר יימחקו."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"הפסקת הגלישה"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"שמחים לראותך שוב!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"האם ברצונך להמשיך בפעילות באתר?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ברצוני להתחיל מחדש"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index b4edfe5..6cd5608 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"ユーザー"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"新しいユーザー"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"インターネット"</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 OFF"</string>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"プロファイルを表示"</string>
     <string name="user_add_user" msgid="4336657383006913022">"ユーザーを追加"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"新しいユーザー"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"ゲスト セッションを終了しますか?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"このセッションでのアプリとデータはすべて削除されます。"</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"セッションを終了"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"おかえりなさい、ゲストさん"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"セッションを続行しますか?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"最初から開始"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 26bde65..52d9f0e 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"მომხმარებელი"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"ახალი მომხმარებელი"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"ინტერნეტი"</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>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"პროფილის ჩვენება"</string>
     <string name="user_add_user" msgid="4336657383006913022">"მომხმარებლის დამატება"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"ახალი მომხმარებელი"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"დასრულდეს სტუმრის სესია?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ამ სესიის ყველა აპი და მონაცემი წაიშლება."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"სესიის დასრულება"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"სტუმარო, გვიხარია, რომ დაბრუნდით!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"გსურთ, თქვენი სესიის გაგრძელება?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ხელახლა დაწყება"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 9ce0a29..fcf8743 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Пайдаланушы"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Жаңа пайдаланушы"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Интернет"</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>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Профильді көрсету"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Пайдаланушы қосу"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Жаңа пайдаланушы"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Қонақ сеансы аяқталсын ба?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Осы сеанстағы барлық қолданбалар мен деректер жойылады."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Сеансты аяқтау"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Қош келдіңіз, қонақ"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Сеансты жалғастыру керек пе?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Қайта бастау"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 1e6c7fa6e..e92bf9b 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"អ្នកប្រើ"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"អ្នកប្រើ​ថ្មី"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"អ៊ីនធឺណិត"</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>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"បង្ហាញ​ប្រវត្តិរូប"</string>
     <string name="user_add_user" msgid="4336657383006913022">"បន្ថែម​អ្នកប្រើ"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"អ្នកប្រើ​ថ្មី"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"បញ្ចប់វគ្គភ្ញៀវឬ?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ទិន្នន័យ និង​កម្មវិធី​ទាំងអស់​ក្នុង​សម័យ​នេះ​នឹង​ត្រូវ​បាន​លុប។"</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"បញ្ចប់វគ្គ"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"សូម​ស្វាគមន៍​ការ​ត្រឡប់​មកវិញ, ភ្ញៀវ!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"តើ​អ្នក​ចង់​បន្ត​សម័យ​របស់​អ្នក​?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ចាប់ផ្ដើម"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 2958b29..d7a0adc 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"ಬಳಕೆದಾರ"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"ಹೊಸ ಬಳಕೆದಾರರು"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"ವೈ-ಫೈ"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"ಇಂಟರ್ನೆಟ್"</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>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"ಪ್ರೊಫೈಲ್‌ ತೋರಿಸು"</string>
     <string name="user_add_user" msgid="4336657383006913022">"ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸಿ"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"ಹೊಸ ಬಳಕೆದಾರರು"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"ಅತಿಥಿ ಸೆಷನ್ ಅಂತ್ಯಗೊಳಿಸುವುದೇ?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ಈ ಸೆಷನ್‌ನಲ್ಲಿನ ಎಲ್ಲ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"ಸೆಷನ್ ಅಂತ್ಯಗೊಳಿಸಿ"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"ಮತ್ತೆ ಸುಸ್ವಾಗತ, ಅತಿಥಿ!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"ನಿಮ್ಮ ಸೆಷನ್‌ ಮುಂದುವರಿಸಲು ಇಚ್ಚಿಸುವಿರಾ?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ಪ್ರಾರಂಭಿಸಿ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index cd613b6..54bcfb9 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"사용자"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"신규 사용자"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"인터넷"</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>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"프로필 표시"</string>
     <string name="user_add_user" msgid="4336657383006913022">"사용자 추가"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"신규 사용자"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"게스트 세션을 종료하시겠습니까?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"이 세션에 있는 모든 앱과 데이터가 삭제됩니다."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"세션 종료"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"게스트 세션 다시 시작"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"세션을 계속 진행하시겠습니까?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"다시 시작"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index e605341..d513380 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -355,8 +355,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Колдонуучу"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Жаңы колдонуучу"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Интернет"</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>
@@ -458,11 +457,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Профилди көрсөтүү"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Колдонуучу кошуу"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Жаңы колдонуучу"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Конок сеансы бүтүрүлсүнбү?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Бул сеанстагы бардык колдонмолор жана дайындар өчүрүлөт."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Сеансты бүтүрүү"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Кайтып келишиңиз менен, конок!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Сеансыңызды улантасызбы?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Кайра баштоо"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index b8cc3de..7e595cd 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"ຜູ້ໃຊ້"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"ຜູ່ໃຊ້ໃໝ່"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi​-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"ອິນເຕີເນັດ"</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>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"​ສະ​ແດງ​ໂປຣ​ໄຟລ໌"</string>
     <string name="user_add_user" msgid="4336657383006913022">"ເພີ່ມຜູ້ໃຊ້"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"ຜູ່ໃຊ້ໃໝ່"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"ສິ້ນສຸດເຊດຊັນແຂກບໍ?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ແອັບຯ​ແລະ​ຂໍ້​ມູນ​ທັງ​ໝົດ​ໃນ​ເຊດ​ຊັນ​ນີ້​ຈະ​ຖືກ​ລຶບ​ອອກ."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"ສິ້ນສຸດເຊດຊັນ"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"ຍິນ​ດີ​ຕ້ອນ​ຮັບ​ກັບ​ມາ, ຜູ່​ຢ້ຽມ​ຢາມ!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"ທ່ານ​ຕ້ອງ​ການ​ສືບ​ຕໍ່​ເຊດ​ຊັນ​ຂອງ​ທ່ານບໍ່?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ເລີ່ມຕົ້ນໃຫມ່"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 8a32436..e0c27a9 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -355,8 +355,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Naudotojas"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Naujas naudotojas"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internetas"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Neprisijungta"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Tinklo nėra"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"„Wi-Fi“ išjungta"</string>
@@ -460,11 +459,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Rodyti profilį"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Pridėti naudotoją"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Naujas naudotojas"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Baigti svečio sesiją?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bus ištrintos visos šios sesijos programos ir duomenys."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Baigti sesiją"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Sveiki sugrįžę, svety!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Ar norite tęsti sesiją?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Pradėti iš naujo"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 56ce376..ff36f51 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -354,8 +354,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Lietotājs"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Jauns lietotājs"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internets"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nav izveidots savienojums"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Nav tīkla"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi ir izslēgts"</string>
@@ -458,11 +457,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Parādīt profilu"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Lietotāja pievienošana"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Jauns lietotājs"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Vai beigt viesa sesiju?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tiks dzēstas visas šīs sesijas lietotnes un dati."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Beigt sesiju"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Laipni lūdzam atpakaļ, viesi!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vai vēlaties turpināt savu sesiju?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Sākt no sākuma"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index fc83bb7..203d8b9 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Корисник"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Нов корисник"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Интернет"</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>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Прикажи го профилот"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Додај корисник"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Нов корисник"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Да се заврши гостинската сесија?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Сите апликации и податоци во сесијата ќе се избришат."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Заврши ја сесијата"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Добре дојде пак, гостине!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Дали сакате да продолжите со сесијата?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Почни одново"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 9cd0412..77925ae 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"ഉപയോക്താവ്"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"പുതിയ ഉപയോക്താവ്"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"വൈഫൈ"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"ഇന്റർനെറ്റ്"</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>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"പ്രൊഫൈൽ കാണിക്കുക"</string>
     <string name="user_add_user" msgid="4336657383006913022">"ഉപയോക്താവിനെ ചേര്‍ക്കുക"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"പുതിയ ഉപയോക്താവ്"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"അതിഥി സെഷൻ അവസാനിപ്പിക്കണോ?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ഈ സെഷനിലെ എല്ലാ അപ്ലിക്കേഷനുകളും ഡാറ്റയും ഇല്ലാതാക്കും."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"സെഷൻ അവസാനിപ്പിക്കുക"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"അതിഥിയ്‌ക്ക് വീണ്ടും സ്വാഗതം!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"നിങ്ങളുടെ സെഷൻ തുടരണോ?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"പുനരാംരംഭിക്കുക"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index b0159b0..c772294 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Хэрэглэгч"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Шинэ хэрэглэгч"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Интернэт"</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>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Профайлыг харуулах"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Хэрэглэгч нэмэх"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Шинэ хэрэглэгч"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Зочны сургалтыг дуусгах уу?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Энэ сешний бүх апп болон дата устах болно."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Сургалтыг дуусгах"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Тавтай морилно уу!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Та үргэлжлүүлэхийг хүсэж байна уу?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Дахин эхлүүлэх"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index b9b525e..d3e3601 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Pengguna"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Pengguna baharu"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Tidak Disambungkan"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Tiada Rangkaian"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi Dimatikan"</string>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Tunjuk profil"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Tambah pengguna"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Pengguna baharu"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Tamatkan sesi tetamu?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Semua apl dan data dalam sesi ini akan dipadam."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Tamatkan sesi"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Selamat kembali, tetamu!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Adakah anda ingin meneruskan sesi anda?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Mulakan semula"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 9801ec6..0c1f9cb 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"အသုံးပြုသူ"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"အသုံးပြုသူ အသစ်"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"အင်တာနက်"</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>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"ပရိုဖိုင်ကို ပြရန်"</string>
     <string name="user_add_user" msgid="4336657383006913022">"အသုံးပြုသူ ထည့်ရန်"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"အသုံးပြုသူ အသစ်"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"ဧည့်သည်စက်ရှင်ကို အဆုံးသတ်မလား။"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ဒီချိတ်ဆက်မှု ထဲက အက်ပ်များ အားလုံး နှင့် ဒေတာကို ဖျက်ပစ်မည်။"</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"သတ်မှတ်ပေးထားသည့်အချိန် ပြီးဆုံးပြီ"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"ပြန်လာတာ ကြိုဆိုပါသည်၊ ဧည့်သည်!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"သင်သည် သင်၏ ချိတ်ဆက်မှုကို ဆက်ပြုလုပ် လိုပါသလား?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"အစမှ ပြန်စပါ"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 6724286..565e7fe 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Bruker"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Ny bruker"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internett"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Ikke tilkoblet"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ingen nettverk"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi er av"</string>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Vis profil"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Legg til brukere"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Ny bruker"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Vil du avslutte gjesteøkten?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle appene og all informasjon i denne økten slettes."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Avslutt økten"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Velkommen tilbake, gjest!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vil du fortsette økten?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start på nytt"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index c104ffd..9d95cf0 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"प्रयोगकर्ता"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"नयाँ प्रयोगकर्ता"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"इन्टरनेट"</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>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"प्रोफाइल देखाउनुहोस्"</string>
     <string name="user_add_user" msgid="4336657383006913022">"प्रयोगकर्ता थप्नुहोस्"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"नयाँ प्रयोगकर्ता"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"अतिथिको सत्र अन्त्य गर्ने हो?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"यस सत्रमा सबै एपहरू र डेटा मेटाइनेछ।"</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"सत्र अन्त्य गर्नुहोस्"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"पुनः स्वागत, अतिथि!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"तपाईं आफ्नो सत्र जारी गर्न चाहनुहुन्छ?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"सुरु गर्नुहोस्"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 7d87817..f598fa3 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Gebruiker"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nieuwe gebruiker"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wifi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Niet verbonden"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Geen netwerk"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wifi uit"</string>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Profiel weergeven"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Gebruiker toevoegen"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Nieuwe gebruiker"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Gastsessie beëindigen?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apps en gegevens in deze sessie worden verwijderd."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Sessie beëindigen"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Welkom terug, gast!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Wil je doorgaan met je sessie?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Opnieuw starten"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 7d7b84f..1e07dd4 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -456,11 +456,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"ପ୍ରୋଫାଇଲ୍ ଦେଖାନ୍ତୁ"</string>
     <string name="user_add_user" msgid="4336657383006913022">"ଉପଯୋଗକର୍ତ୍ତାଙ୍କୁ ଯୋଗ କରନ୍ତୁ"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"ନୂଆ ଉପଯୋଗକର୍ତ୍ତା"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"ଅତିଥି ସେସନ୍ ଶେଷ କରିବେ?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ଏହି ଅବଧିର ସମସ୍ତ ଆପ୍‌ ଓ ଡାଟା ଡିଲିଟ୍‌ ହୋଇଯିବ।"</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"ସେସନ୍ ଶେଷ କରନ୍ତୁ"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"ପୁଣି ସ୍ୱାଗତ, ଅତିଥି!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"ଆପଣ ନିଜର ଅବଧି ଜାରି ରଖିବାକୁ ଚାହାନ୍ତି କି?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ଆରମ୍ଭ କରନ୍ତୁ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 8a19e28..561e70d 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -355,8 +355,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Użytkownik"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nowy użytkownik"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Brak połączenia"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Brak sieci"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi wyłączone"</string>
@@ -460,11 +459,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Pokaż profil"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Dodaj użytkownika"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Nowy użytkownik"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Zakończyć sesję gościa?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Wszystkie aplikacje i dane w tej sesji zostaną usunięte."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Zakończ sesję"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Witaj ponownie, gościu!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Chcesz kontynuować sesję?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Rozpocznij nową"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 57b924d..7fe53d3 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Usuário"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Novo usuário"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</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>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Mostrar perfil"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Adicionar usuário"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Novo usuário"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Encerrar sessão de visitante?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todos os apps e dados nesta sessão serão excluídos."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Encerrar sessão"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Bem-vindo, convidado."</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Quer continuar a sessão?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recomeçar"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index e39f757c..dd154e8 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Utilizador"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Novo utilizador"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</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>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Mostrar perfil"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Adicionar utilizador"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Novo utilizador"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Pretende terminar a sessão de convidado?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todas as aplicações e dados desta sessão serão eliminados."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Terminar sessão"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Bem-vindo de volta, caro(a) convidado(a)!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Pretende continuar a sessão?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recomeçar"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 57b924d..7fe53d3 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Usuário"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Novo usuário"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</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>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Mostrar perfil"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Adicionar usuário"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Novo usuário"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Encerrar sessão de visitante?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todos os apps e dados nesta sessão serão excluídos."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Encerrar sessão"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Bem-vindo, convidado."</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Quer continuar a sessão?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recomeçar"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index acbe801..317fc09 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -354,8 +354,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Utilizator"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Utilizator nou"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Neconectată"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Nicio rețea"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi deconectat"</string>
@@ -458,11 +457,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Afișați profilul"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Adăugați un utilizator"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Utilizator nou"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Încheiați sesiunea pentru invitați?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toate aplicațiile și datele din această sesiune vor fi șterse."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Încheiați sesiunea"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Bine ați revenit în sesiunea pentru invitați!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vreți să continuați sesiunea?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Începeți din nou"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index c59bd2ae..bbb014e 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -355,8 +355,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Пользователь"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Новый пользователь"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Интернет"</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>
@@ -460,11 +459,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Показать профиль."</string>
     <string name="user_add_user" msgid="4336657383006913022">"Добавить пользователя"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Новый пользователь"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Завершить гостевой сеанс?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Все приложения и данные этого профиля будут удалены."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Завершить сеанс"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Рады видеть вас снова!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Продолжить сеанс?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Начать заново"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index a49ca86..a7a2bb7 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"පරිශීලක"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"නව පරිශීලකයා"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"අන්තර්ජාලය"</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>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"පැතිකඩ පෙන්වන්න"</string>
     <string name="user_add_user" msgid="4336657383006913022">"පරිශීලකයෙක් එක් කරන්න"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"නව පරිශීලකයා"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"ආරාධිත සැසිය අවසන් කරන්නද?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"මෙම සැසියේ සියළුම යෙදුම් සහ දත්ත මකාවී."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"සැසිය අවසන් කරන්න"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"නැවත සාදරයෙන් පිළිගනිමු, අමුත්තා!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"ඔබගේ සැසිය දිගටම කරගෙන යෑමට ඔබට අවශ්‍යද?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"යළි මුල සිට අරඹන්න"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index fe63b70..7eb5297 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -355,8 +355,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Používateľ"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nový používateľ"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi‑Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nepripojené"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Žiadna sieť"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Sieť Wi‑Fi je vypnutá"</string>
@@ -460,11 +459,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Zobraziť profil"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Pridať používateľa"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Nový používateľ"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Chcete ukončiť reláciu hosťa?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Všetky aplikácie a údaje v tejto relácii budú odstránené."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Ukončiť reláciu"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Hosť, vitajte späť!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Chcete v relácii pokračovať?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Začať odznova"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 85956d6..6d23f26 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -355,8 +355,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Uporabnik"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nov uporabnik"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Povezava ni vzpostavljena"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ni omrežja"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi izklopljen"</string>
@@ -460,11 +459,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Prikaz profila"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Dodajanje uporabnika"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Nov uporabnik"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Želite končati sejo gosta?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Vse aplikacije in podatki v tej seji bodo izbrisani."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Končaj sejo"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Znova pozdravljeni, gost!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite nadaljevati sejo?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Začni znova"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 733db0e..7e89b93 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Përdoruesi"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Përdorues i ri"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nuk është i lidhur"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Nuk ka rrjet"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi është i çaktivizuar"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index c5414a4..af5175c 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -354,8 +354,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Корисник"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Нови корисник"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"WiFi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Интернет"</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">"WiFi је искључен"</string>
@@ -458,11 +457,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Прикажи профил"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Додај корисника"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Нови корисник"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Желите да завршите сесију госта?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Све апликације и подаци у овој сесији ће бити избрисани."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Заврши сесију"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Добро дошли назад, госте!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Желите ли да наставите сесију?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Почни из почетка"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index d2c993a0..41bca7c 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Användare"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Ny användare"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Ej ansluten"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Inget nätverk"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi av"</string>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Visa profil"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Lägg till användare"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Ny användare"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Vill du avsluta gästsessionen?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alla appar och data i denna session kommer att raderas."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Avsluta session"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Välkommen tillbaka gäst!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vill du fortsätta sessionen?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Börja om"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 29045f3..f122013 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Mtumiaji"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Mtumiaji mpya"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Intaneti"</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>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Onyesha wasifu"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Ongeza mtumiaji"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Mtumiaji mpya"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Ungependa kumaliza kipindi cha mgeni?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Data na programu zote katika kipindi hiki zitafutwa."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Maliza kipindi"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Karibu tena, mwalikwa!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Je, unataka kuendelea na kipindi chako?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Anza tena"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 2ca6720..c076a03 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"பயனர்"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"புதியவர்"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"வைஃபை"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"இணையம்"</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>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"சுயவிவரத்தைக் காட்டு"</string>
     <string name="user_add_user" msgid="4336657383006913022">"பயனரைச் சேர்"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"புதியவர்"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"விருந்தினர் அமர்வை நிறைவுசெய்யவா?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"இந்த அமர்வின் எல்லா பயன்பாடுகளும், தரவும் நீக்கப்படும்."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"அமர்வை நிறைவுசெய்"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"நல்வரவு!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"உங்கள் அமர்வைத் தொடர விருப்பமா?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"மீண்டும் தொடங்கு"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 9ce5fc7..fca5107 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"వినియోగదారు"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"కొత్త వినియోగదారు"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"ఇంటర్నెట్"</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>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"ప్రొఫైల్‌ని చూపు"</string>
     <string name="user_add_user" msgid="4336657383006913022">"వినియోగదారుని జోడించండి"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"కొత్త వినియోగదారు"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"గెస్ట్ సెషన్‌ను ముగించాలా?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ఈ సెషన్‌లోని అన్ని అనువర్తనాలు మరియు డేటా తొలగించబడతాయి."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"సెషన్‌ను ముగించు"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"పునఃస్వాగతం, అతిథి!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"మీరు మీ సెషన్‌ని కొనసాగించాలనుకుంటున్నారా?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"మొదటి నుండి ప్రారంభించు"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 900012e..c909d37 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"ผู้ใช้"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"ผู้ใช้ใหม่"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"อินเทอร์เน็ต"</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">"ปิด WiFi"</string>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"แสดงโปรไฟล์"</string>
     <string name="user_add_user" msgid="4336657383006913022">"เพิ่มผู้ใช้"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"ผู้ใช้ใหม่"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"จบเซสชันผู้เยี่ยมชมใช่ไหม"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ระบบจะลบแอปและข้อมูลทั้งหมดในเซสชันนี้"</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"จบเซสชัน"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"ยินดีต้อนรับท่านผู้เยี่ยมชมกลับมาอีกครั้ง!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"คุณต้องการอยู่ในเซสชันต่อไปไหม"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"เริ่มต้นใหม่"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index f531de5..2e75fa3 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"User"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Bagong user"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Hindi Nakakonekta"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Walang Network"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Naka-off ang Wi-Fi"</string>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Ipakita ang profile"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Magdagdag ng user"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Bagong user"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Tapusin ang session ng bisita?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Ide-delete ang lahat ng app at data sa session na ito."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Tapusin ang session"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Maligayang pagbabalik, bisita!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Gusto mo bang ipagpatuloy ang iyong session?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Magsimulang muli"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index ba70531..98552b1 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Kullanıcı"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Yeni kullanıcı"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Kablosuz"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"İnternet"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Bağlı Değil"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ağ yok"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Kablosuz Kapalı"</string>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Profili göster"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Kullanıcı ekle"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Yeni kullanıcı"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Misafir oturumu sonlandırılsın mı?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bu oturumdaki tüm uygulamalar ve veriler silinecek."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Oturumu sonlandır"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Tekrar hoş geldiniz sayın misafir!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Oturumunuza devam etmek istiyor musunuz?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Baştan başla"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index b2ae569..b70d36a 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -355,8 +355,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Користувач"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Новий користувач"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Інтернет"</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>
@@ -460,11 +459,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Показати профіль"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Додати користувача"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Новий користувач"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Завершити сеанс у режимі \"Гість\"?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Усі додатки й дані з цього сеансу буде видалено."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Завершити сеанс"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"З поверненням!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Продовжити сеанс?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Почати знову"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 06a448b..bbadf6a 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"صارف"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"نیا صارف"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"انٹرنیٹ"</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>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"پروفائل دکھائیں"</string>
     <string name="user_add_user" msgid="4336657383006913022">"صارف کو شامل کریں"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"نیا صارف"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"مہمان سیشن ختم کریں؟"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"اس سیشن میں موجود سبھی ایپس اور ڈیٹا کو حذف کر دیا جائے گا۔"</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"سیشن ختم کریں"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"مہمان، پھر سے خوش آمدید!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"کیا آپ اپنا سیشن جاری رکھنا چاہتے ہیں؟"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"دوبارہ شروع کریں"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index e1add65..a20676d 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Foydalanuvchi"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Yangi foydalanuvchi"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</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 021044d..5de7df6a 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Người dùng"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Người dùng mới"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Chưa được kết nối"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Không có mạng nào"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Tắt Wi-Fi"</string>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Hiển thị hồ sơ"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Thêm người dùng"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Người dùng mới"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Kết thúc phiên khách?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tất cả ứng dụng và dữ liệu trong phiên này sẽ bị xóa."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Kết thúc phiên"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Chào mừng bạn trở lại!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Bạn có muốn tiếp tục phiên của mình không?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Bắt đầu lại"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 60acb83..7f3f394 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"用户"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"新用户"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"WLAN"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"互联网"</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">"WLAN:关闭"</string>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"显示个人资料"</string>
     <string name="user_add_user" msgid="4336657383006913022">"添加用户"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"新用户"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"要结束访客会话吗?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"此会话中的所有应用和数据都将被删除。"</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"结束会话"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"访客,欢迎回来!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"要继续您的会话吗?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"重新开始"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index db55580..485f1cf 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"使用者"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"新使用者"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"互聯網"</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>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"顯示個人檔案"</string>
     <string name="user_add_user" msgid="4336657383006913022">"加入使用者"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"新使用者"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"要結束訪客工作階段嗎?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"這個工作階段中的所有應用程式和資料都會被刪除。"</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"結束工作階段"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"訪客您好,歡迎回來!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"您要繼續您的工作階段嗎?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"重新開始"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 1487ad3..1edeacd 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"使用者"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"新使用者"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"網際網路"</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>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"顯示設定檔"</string>
     <string name="user_add_user" msgid="4336657383006913022">"新增使用者"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"新使用者"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"要結束訪客工作階段嗎?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"這個工作階段中的所有應用程式和資料都會遭到刪除。"</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"結束工作階段"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"訪客你好,歡迎回來!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"你要繼續這個工作階段嗎?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"重新開始"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index b0f084b..58baebc 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -353,8 +353,7 @@
     <string name="quick_settings_user_title" msgid="8673045967216204537">"Umsebenzisi"</string>
     <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Umsebenzisi omusha"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"I-Wi-Fi"</string>
-    <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
-    <skip />
+    <string name="quick_settings_internet_label" msgid="6603068555872455463">"I-inthanethi"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Akuxhunyiwe"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ayikho inethiwekhi"</string>
     <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"I-Wi-Fi icimile"</string>
@@ -456,11 +455,9 @@
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Bonisa iphrofayela"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Engeza umsebenzisi"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Umsebenzisi omusha"</string>
-    <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Misa isikhathi sesihambeli?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Zonke izinhlelo zokusebenza nedatha kulesi sikhathi zizosuswa."</string>
-    <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
-    <skip />
+    <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Phothula iseshini"</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Siyakwamukela futhi, sivakashi!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Ingabe ufuna ukuqhubeka ngesikhathi sakho?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Qala phansi"</string>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 6f69483..8888ad6 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1041,6 +1041,13 @@
          burn-in on AOD. -->
     <dimen name="burn_in_prevention_offset_y">50dp</dimen>
 
+    <!-- The maximum offset in either direction that elements are moved vertically to prevent
+         burn-in on AOD. -->
+    <dimen name="burn_in_prevention_offset_y_large_clock">42dp</dimen>
+
+    <!-- Large clock maximum font size (dp is intentional, to prevent any further scaling) -->
+    <dimen name="large_clock_text_size">150dp</dimen>
+
     <!-- The maximum offset in either direction that icons move to prevent burn-in on AOD. -->
     <dimen name="default_burn_in_prevention_offset">15dp</dimen>
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 6cc863a4..2d972e0 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -24,6 +24,7 @@
 import android.widget.FrameLayout;
 import android.widget.RelativeLayout;
 import android.widget.TextClock;
+import android.widget.TextView;
 
 import com.android.internal.colorextraction.ColorExtractor;
 import com.android.keyguard.dagger.KeyguardStatusViewScope;
@@ -147,6 +148,10 @@
         setTextSize(TypedValue.COMPLEX_UNIT_PX, mContext.getResources()
                 .getDimensionPixelSize(R.dimen.widget_big_font_size));
 
+        ((TextView) mNewLockscreenLargeClockFrame.getChildAt(0))
+                .setTextSize(TypedValue.COMPLEX_UNIT_PX, mContext.getResources()
+                        .getDimensionPixelSize(R.dimen.large_clock_text_size));
+
         mClockSwitchYAmount = mContext.getResources().getDimensionPixelSize(
                 R.dimen.keyguard_clock_switch_y_shift);
     }
@@ -391,7 +396,6 @@
         if (hasVisibleNotifications == mHasVisibleNotifications) {
             return;
         }
-
         animateClockChange(!hasVisibleNotifications);
 
         mHasVisibleNotifications = hasVisibleNotifications;
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 08262de..eefae5b 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -111,7 +111,8 @@
                     .setBubbles(mWMComponent.getBubbles())
                     .setHideDisplayCutout(mWMComponent.getHideDisplayCutout())
                     .setShellCommandHandler(mWMComponent.getShellCommandHandler())
-                    .setAppPairs(mWMComponent.getAppPairs());
+                    .setAppPairs(mWMComponent.getAppPairs())
+                    .setTaskViewFactory(mWMComponent.getTaskViewFactory());
         } else {
             // TODO: Call on prepareSysUIComponentBuilder but not with real components. Other option
             // is separating this logic into newly creating SystemUITestsFactory.
@@ -122,7 +123,8 @@
                     .setBubbles(Optional.ofNullable(null))
                     .setHideDisplayCutout(Optional.ofNullable(null))
                     .setShellCommandHandler(Optional.ofNullable(null))
-                    .setAppPairs(Optional.ofNullable(null));
+                    .setAppPairs(Optional.ofNullable(null))
+                    .setTaskViewFactory(Optional.ofNullable(null));
         }
         mSysUIComponent = builder.build();
         if (initializeComponents) {
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index c289ca2..1036c99 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -18,6 +18,7 @@
 
 import static android.media.AudioManager.ACTION_MICROPHONE_MUTE_CHANGED;
 
+import android.Manifest;
 import android.app.AppOpsManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -30,6 +31,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.UserHandle;
+import android.provider.DeviceConfig;
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.SparseArray;
@@ -75,6 +77,8 @@
     private final AppOpsManager mAppOps;
     private final AudioManager mAudioManager;
     private final LocationManager mLocationManager;
+    // TODO ntmyren: remove t
+    private final PackageManager mPackageManager;
 
     // mLocationProviderPackages are cached and updated only occasionally
     private static final long LOCATION_PROVIDER_UPDATE_FREQUENCY_MS = 30000;
@@ -127,6 +131,7 @@
         mAudioManager = audioManager;
         mMicMuted = audioManager.isMicrophoneMute();
         mLocationManager = context.getSystemService(LocationManager.class);
+        mPackageManager = context.getPackageManager();
         dumpManager.registerDumpable(TAG, this);
     }
 
@@ -334,6 +339,16 @@
         return mLocationProviderPackages.contains(packageName);
     }
 
+    // TODO ntmyren: remove after teamfood is finished
+    private boolean shouldShowAppPredictor(String pkgName) {
+        if (!DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, "permissions_hub_2_enabled",
+                false)) {
+            return false;
+        }
+        return mPackageManager.checkPermission(Manifest.permission.MANAGE_APP_PREDICTIONS, pkgName)
+                == PackageManager.PERMISSION_GRANTED;
+    }
+
     /**
      * Does the app-op, uid and package name, refer to an operation that should be shown to the
      * user. Only specficic ops (like {@link AppOpsManager.OP_SYSTEM_ALERT_WINDOW}) or
@@ -353,8 +368,9 @@
                 || appOpCode == AppOpsManager.OP_PHONE_CALL_MICROPHONE) {
             return true;
         }
-
-        if (appOpCode == AppOpsManager.OP_CAMERA && isLocationProvider(packageName)) {
+        // TODO ntmyren: Replace this with more robust check if this moves beyond teamfood
+        if ((appOpCode == AppOpsManager.OP_CAMERA && isLocationProvider(packageName))
+                || shouldShowAppPredictor(packageName)) {
             return true;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt
index 6c28d11..ff55b76d 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt
@@ -26,7 +26,9 @@
 import android.service.controls.actions.ModeAction
 import android.text.InputType
 import android.util.Log
+import android.view.LayoutInflater
 import android.view.WindowManager
+import android.view.inputmethod.InputMethodManager
 import android.widget.CheckBox
 import android.widget.EditText
 
@@ -71,11 +73,21 @@
                 R.string.controls_pin_instructions
             )
         }
-        val builder = AlertDialog.Builder(cvh.context, STYLE).apply {
+        return object : AlertDialog(cvh.context, STYLE) {
+            override fun dismiss() {
+                window?.decorView?.let {
+                    // workaround for b/159309083
+                    it.context.getSystemService(InputMethodManager::class.java)
+                            ?.hideSoftInputFromWindow(it.windowToken, 0)
+                }
+                super.dismiss()
+            }
+        }.apply {
             setTitle(title)
-            setView(R.layout.controls_dialog_pin)
-            setPositiveButton(
-                android.R.string.ok,
+            setView(LayoutInflater.from(context).inflate(R.layout.controls_dialog_pin, null))
+            setButton(
+                DialogInterface.BUTTON_POSITIVE,
+                context.getText(android.R.string.ok),
                 DialogInterface.OnClickListener { dialog, _ ->
                     if (dialog is Dialog) {
                         dialog.requireViewById<EditText>(R.id.controls_pin_input)
@@ -85,15 +97,15 @@
                         dialog.dismiss()
                     }
             })
-            setNegativeButton(
-                android.R.string.cancel,
+            setButton(
+                DialogInterface.BUTTON_NEGATIVE,
+                context.getText(android.R.string.cancel),
                 DialogInterface.OnClickListener { dialog, _ ->
                     onCancel.invoke()
                     dialog.cancel()
                 }
             )
-        }
-        return builder.create().apply {
+
             getWindow().apply {
                 setType(WINDOW_TYPE)
                 setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
index ab82225..7cd7e18 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
@@ -36,6 +36,8 @@
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.wm.shell.TaskViewFactory
+import java.util.Optional
 import javax.inject.Inject
 
 @SysUISingleton
@@ -45,7 +47,8 @@
     @Main private val uiExecutor: DelayableExecutor,
     private val activityStarter: ActivityStarter,
     private val keyguardStateController: KeyguardStateController,
-    private val globalActionsComponent: GlobalActionsComponent
+    private val globalActionsComponent: GlobalActionsComponent,
+    private val taskViewFactory: Optional<TaskViewFactory>
 ) : ControlActionCoordinator {
     private var dialog: Dialog? = null
     private val vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
@@ -163,11 +166,13 @@
 
             uiExecutor.execute {
                 // make sure the intent is valid before attempting to open the dialog
-                if (activities.isNotEmpty()) {
-                    dialog = DetailDialog(cvh, intent).also {
-                        it.setOnDismissListener { _ -> dialog = null }
-                        it.show()
-                    }
+                if (activities.isNotEmpty() && taskViewFactory.isPresent) {
+                    taskViewFactory.get().create(cvh.context, uiExecutor, {
+                        dialog = DetailDialog(cvh, it, intent).also {
+                            it.setOnDismissListener { _ -> dialog = null }
+                            it.show()
+                        }
+                    })
                 } else {
                     cvh.setErrorStatus()
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
index 5b11627..e4f9064 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
@@ -16,8 +16,12 @@
 
 package com.android.systemui.controls.ui
 
-import android.app.ActivityView
+import android.app.ActivityOptions
+import android.app.ActivityTaskManager
+import android.app.ActivityTaskManager.INVALID_TASK_ID
 import android.app.Dialog
+import android.app.PendingIntent
+import android.content.ComponentName
 import android.content.Intent
 import android.provider.Settings
 import android.view.View
@@ -26,9 +30,9 @@
 import android.view.WindowInsets.Type
 import android.view.WindowManager
 import android.widget.ImageView
-
 import com.android.internal.policy.ScreenDecorationsUtils
 import com.android.systemui.R
+import com.android.wm.shell.TaskView
 
 /**
  * A dialog that provides an {@link ActivityView}, allowing the application to provide
@@ -37,6 +41,7 @@
  */
 class DetailDialog(
     val cvh: ControlViewHolder,
+    val activityView: TaskView,
     val intent: Intent
 ) : Dialog(cvh.context, R.style.Theme_SystemUI_Dialog_Control_DetailPanel) {
 
@@ -49,10 +54,16 @@
         private const val EXTRA_USE_PANEL = "controls.DISPLAY_IN_PANEL"
     }
 
-    var activityView = ActivityView(context)
+    var detailTaskId = INVALID_TASK_ID
 
-    val stateCallback: ActivityView.StateCallback = object : ActivityView.StateCallback() {
-        override fun onActivityViewReady(view: ActivityView) {
+    fun removeDetailTask() {
+        if (detailTaskId == INVALID_TASK_ID) return
+        ActivityTaskManager.getInstance().removeTask(detailTaskId)
+        detailTaskId = INVALID_TASK_ID
+    }
+
+    val stateCallback = object : TaskView.Listener {
+        override fun onInitialized() {
             val launchIntent = Intent(intent)
             launchIntent.putExtra(EXTRA_USE_PANEL, true)
 
@@ -60,18 +71,31 @@
             launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT)
             launchIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
 
-            view.startActivity(launchIntent)
+            activityView.startActivity(
+                    PendingIntent.getActivity(context, 0, launchIntent,
+                            PendingIntent.FLAG_UPDATE_CURRENT), null, ActivityOptions.makeBasic())
         }
 
-        override fun onActivityViewDestroyed(view: ActivityView) {}
-
         override fun onTaskRemovalStarted(taskId: Int) {
+            detailTaskId = INVALID_TASK_ID
             dismiss()
         }
+
+        override fun onTaskCreated(taskId: Int, name: ComponentName?) {
+            detailTaskId = taskId
+        }
+
+        override fun onReleased() {
+            removeDetailTask()
+        }
     }
 
     init {
         window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY)
+        // To pass touches to the task inside TaskView.
+        window.addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)
+        window.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY)
+
         setContentView(R.layout.controls_detail_dialog)
 
         requireViewById<ViewGroup>(R.id.controls_activity_view).apply {
@@ -84,6 +108,9 @@
 
         requireViewById<ImageView>(R.id.control_detail_open_in_app).apply {
             setOnClickListener { v: View ->
+                // Remove the task explicitly, since onRelease() callback will be executed after
+                // startActivity() below is called.
+                removeDetailTask()
                 dismiss()
                 context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
                 v.context.startActivity(intent)
@@ -126,7 +153,7 @@
     }
 
     override fun show() {
-        activityView.setCallback(stateCallback)
+        activityView.setListener(cvh.uiExecutor, stateCallback)
 
         super.show()
     }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index f9505de..612a559 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -25,6 +25,7 @@
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.util.InjectionInflationController;
 import com.android.wm.shell.ShellCommandHandler;
+import com.android.wm.shell.TaskViewFactory;
 import com.android.wm.shell.apppairs.AppPairs;
 import com.android.wm.shell.bubbles.Bubbles;
 import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
@@ -71,6 +72,9 @@
         Builder setBubbles(Optional<Bubbles> b);
 
         @BindsInstance
+        Builder setTaskViewFactory(Optional<TaskViewFactory> t);
+
+        @BindsInstance
         Builder setHideDisplayCutout(Optional<HideDisplayCutout> h);
 
         @BindsInstance
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index 943a54e..c75dc84 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -19,6 +19,7 @@
 import com.android.systemui.wmshell.WMShellModule;
 import com.android.wm.shell.ShellCommandHandler;
 import com.android.wm.shell.ShellInit;
+import com.android.wm.shell.TaskViewFactory;
 import com.android.wm.shell.apppairs.AppPairs;
 import com.android.wm.shell.bubbles.Bubbles;
 import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
@@ -79,4 +80,7 @@
 
     @WMSingleton
     Optional<HideDisplayCutout> getHideDisplayCutout();
+
+    @WMSingleton
+    Optional<TaskViewFactory> getTaskViewFactory();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java
index 4efe4d8..f0e4cce 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java
@@ -461,14 +461,8 @@
     @Override
     public void draw(Canvas canvas) {
         if (mHasOvalBg) {
-            canvas.save();
-            int cx = (getLeft() + getRight()) / 2;
-            int cy = (getTop() + getBottom()) / 2;
-            canvas.translate(cx, cy);
             int d = Math.min(getWidth(), getHeight());
-            int r = d / 2;
-            canvas.drawOval(-r, -r, r, r, mOvalBgPaint);
-            canvas.restore();
+            canvas.drawOval(0, 0, d, d, mOvalBgPaint);
         }
         super.draw(canvas);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index c2ba344..aa8d710 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -130,7 +130,7 @@
         }
     }
 
-    private WindowManager.LayoutParams getWindowLayoutParams() {
+    protected WindowManager.LayoutParams getWindowLayoutParams() {
         final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT,
                 ViewGroup.LayoutParams.MATCH_PARENT,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
index 3811ca9..bbc4b78 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
@@ -50,18 +50,26 @@
     @Inject
     public FeatureFlags(@Background Executor executor) {
         DeviceConfig.addOnPropertiesChangedListener(
-                "systemui",
+                /* namespace= */ "systemui",
                 executor,
                 this::onPropertiesChanged);
     }
 
     public boolean isNewNotifPipelineEnabled() {
-        return getDeviceConfigFlag("notification.newpipeline.enabled", true);
+        return getDeviceConfigFlag("notification.newpipeline.enabled", /* defaultValue= */ true);
     }
 
     public boolean isNewNotifPipelineRenderingEnabled() {
         return isNewNotifPipelineEnabled()
-                && getDeviceConfigFlag("notification.newpipeline.rendering", false);
+                && getDeviceConfigFlag("notification.newpipeline.rendering", /* defaultValue= */
+                false);
+    }
+
+    /**
+     * Flag used for guarding development of b/171917882.
+     */
+    public boolean isTwoColumnNotificationShadeEnabled() {
+        return getDeviceConfigFlag("notification.twocolumn", /* defaultValue= */ false);
     }
 
     private void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
@@ -76,7 +84,7 @@
         synchronized (mCachedDeviceConfigFlags) {
             Boolean flag = mCachedDeviceConfigFlags.get(key);
             if (flag == null) {
-                flag = DeviceConfig.getBoolean("systemui", key, defaultValue);
+                flag = DeviceConfig.getBoolean(/* namespace= */ "systemui", key, defaultValue);
                 mCachedDeviceConfigFlags.put(key, flag);
             }
             return flag;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
index 28ee935..97201f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
@@ -134,12 +134,14 @@
     /** Shows or hides feedback indicator */
     @Override
     public void showFeedbackIcon(boolean show, Pair<Integer, Integer> resIds) {
-        mFeedbackIcon.setVisibility(show ? View.VISIBLE : View.GONE);
-        if (show) {
-            if (mFeedbackIcon instanceof ImageButton) {
-                ((ImageButton) mFeedbackIcon).setImageResource(resIds.first);
+        if (mFeedbackIcon != null) {
+            mFeedbackIcon.setVisibility(show ? View.VISIBLE : View.GONE);
+            if (show) {
+                if (mFeedbackIcon instanceof ImageButton) {
+                    ((ImageButton) mFeedbackIcon).setImageResource(resIds.first);
+                }
+                mFeedbackIcon.setContentDescription(mView.getContext().getString(resIds.second));
             }
-            mFeedbackIcon.setContentDescription(mView.getContext().getString(resIds.second));
         }
     }
 
@@ -263,7 +265,9 @@
         mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_ICON, mIcon);
         mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_EXPANDER,
                 mExpandButton);
-        mTransformationHelper.addViewTransformingToSimilar(mWorkProfileImage);
+        if (mWorkProfileImage != null) {
+            mTransformationHelper.addViewTransformingToSimilar(mWorkProfileImage);
+        }
         if (mIsLowPriority && mHeaderText != null) {
             mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TITLE,
                     mHeaderText);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 6da5d1b9..6cd7a74 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -112,6 +112,11 @@
     private int mBurnInPreventionOffsetY;
 
     /**
+     * Burn-in prevention y translation for large clock layouts.
+     */
+    private int mBurnInPreventionOffsetYLargeClock;
+
+    /**
      * Doze/AOD transition amount.
      */
     private float mDarkAmount;
@@ -156,6 +161,8 @@
                 R.dimen.burn_in_prevention_offset_x);
         mBurnInPreventionOffsetY = res.getDimensionPixelSize(
                 R.dimen.burn_in_prevention_offset_y);
+        mBurnInPreventionOffsetYLargeClock = res.getDimensionPixelSize(
+                R.dimen.burn_in_prevention_offset_y_large_clock);
     }
 
     /**
@@ -287,8 +294,12 @@
     }
 
     private float burnInPreventionOffsetY() {
-        return getBurnInOffset(mBurnInPreventionOffsetY * 2, false /* xAxis */)
-                - mBurnInPreventionOffsetY;
+        int offset = mBurnInPreventionOffsetY;
+        if (mLockScreenMode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL) {
+            offset = mBurnInPreventionOffsetYLargeClock;
+        }
+
+        return getBurnInOffset(offset * 2, false /* xAxis */) - offset;
     }
 
     private float burnInPreventionOffsetX() {
diff --git a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
index 0d63324..0ba072e 100644
--- a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
+++ b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
@@ -25,7 +25,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
-import com.android.wm.shell.pip.tv.PipNotification;
+import com.android.wm.shell.pip.tv.TvPipNotificationController;
 
 import java.util.Arrays;
 
@@ -36,7 +36,7 @@
     public static String GENERAL     = "GEN";
     public static String STORAGE     = "DSK";
     public static String BATTERY     = "BAT";
-    public static String TVPIP       = PipNotification.NOTIFICATION_CHANNEL_TVPIP;
+    public static String TVPIP       = TvPipNotificationController.NOTIFICATION_CHANNEL; // "TVPIP"
     public static String HINTS       = "HNT";
 
     public NotificationChannels(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
index 4d3af9c..8a79ace 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
@@ -32,9 +32,9 @@
 import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
 import com.android.wm.shell.pip.PipTaskOrganizer;
 import com.android.wm.shell.pip.PipUiEventLogger;
-import com.android.wm.shell.pip.tv.PipController;
-import com.android.wm.shell.pip.tv.PipNotification;
+import com.android.wm.shell.pip.tv.TvPipController;
 import com.android.wm.shell.pip.tv.TvPipMenuController;
+import com.android.wm.shell.pip.tv.TvPipNotificationController;
 
 import java.util.Optional;
 
@@ -55,31 +55,24 @@
             PipTaskOrganizer pipTaskOrganizer,
             TvPipMenuController tvPipMenuController,
             PipMediaController pipMediaController,
-            PipNotification pipNotification,
+            TvPipNotificationController tvPipNotificationController,
             TaskStackListenerImpl taskStackListener,
             WindowManagerShellWrapper windowManagerShellWrapper) {
         return Optional.of(
-                new PipController(
+                new TvPipController(
                         context,
                         pipBoundsState,
                         pipBoundsAlgorithm,
                         pipTaskOrganizer,
                         tvPipMenuController,
                         pipMediaController,
-                        pipNotification,
+                        tvPipNotificationController,
                         taskStackListener,
                         windowManagerShellWrapper));
     }
 
     @WMSingleton
     @Provides
-    static PipNotification providePipNotification(Context context,
-            PipMediaController pipMediaController) {
-        return new PipNotification(context, pipMediaController);
-    }
-
-    @WMSingleton
-    @Provides
     static PipBoundsAlgorithm providePipBoundsHandler(Context context,
             PipBoundsState pipBoundsState) {
         return new PipBoundsAlgorithm(context, pipBoundsState);
@@ -93,7 +86,7 @@
 
     @WMSingleton
     @Provides
-    static TvPipMenuController providesPipTvMenuController(
+    static TvPipMenuController providesTvPipMenuController(
             Context context,
             PipBoundsState pipBoundsState,
             SystemWindows systemWindows,
@@ -103,15 +96,22 @@
 
     @WMSingleton
     @Provides
+    static TvPipNotificationController provideTvPipNotificationController(Context context,
+            PipMediaController pipMediaController) {
+        return new TvPipNotificationController(context, pipMediaController);
+    }
+
+    @WMSingleton
+    @Provides
     static PipTaskOrganizer providePipTaskOrganizer(Context context,
-            TvPipMenuController tvMenuController,
+            TvPipMenuController tvPipMenuController,
             PipBoundsState pipBoundsState,
             PipBoundsAlgorithm pipBoundsAlgorithm,
             PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
             Optional<LegacySplitScreen> splitScreenOptional, DisplayController displayController,
             PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer) {
         return new PipTaskOrganizer(context, pipBoundsState, pipBoundsAlgorithm,
-                tvMenuController, pipSurfaceTransactionHelper, splitScreenOptional,
+                tvPipMenuController, pipSurfaceTransactionHelper, splitScreenOptional,
                 displayController, pipUiEventLogger, shellTaskOrganizer);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
index 1d3f26e7..e20cd44 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
@@ -21,7 +21,6 @@
 
 import com.android.systemui.dagger.WMSingleton;
 import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.Transitions;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayImeController;
 import com.android.wm.shell.common.ShellExecutor;
@@ -32,6 +31,7 @@
 import com.android.wm.shell.common.annotations.ShellMainThread;
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
+import com.android.wm.shell.transition.Transitions;
 
 import dagger.Module;
 import dagger.Provides;
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index b46751d..572b15d 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -40,7 +40,8 @@
 import com.android.wm.shell.ShellInit;
 import com.android.wm.shell.ShellInitImpl;
 import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.Transitions;
+import com.android.wm.shell.TaskViewFactory;
+import com.android.wm.shell.TaskViewFactoryController;
 import com.android.wm.shell.WindowManagerShellWrapper;
 import com.android.wm.shell.apppairs.AppPairs;
 import com.android.wm.shell.bubbles.BubbleController;
@@ -60,6 +61,7 @@
 import com.android.wm.shell.draganddrop.DragAndDropController;
 import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
 import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController;
+import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
 import com.android.wm.shell.onehanded.OneHanded;
 import com.android.wm.shell.onehanded.OneHandedController;
 import com.android.wm.shell.pip.Pip;
@@ -68,10 +70,9 @@
 import com.android.wm.shell.pip.PipUiEventLogger;
 import com.android.wm.shell.pip.phone.PipAppOpsListener;
 import com.android.wm.shell.pip.phone.PipTouchHandler;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
+import com.android.wm.shell.transition.Transitions;
 
 import java.util.Optional;
-import java.util.concurrent.TimeUnit;
 
 import dagger.BindsOptionalOf;
 import dagger.Module;
@@ -175,6 +176,7 @@
             Optional<LegacySplitScreen> legacySplitScreenOptional,
             Optional<AppPairs> appPairsOptional,
             FullscreenTaskListener fullscreenTaskListener,
+            Transitions transitions,
             @ShellMainThread ShellExecutor shellMainExecutor) {
         return ShellInitImpl.create(displayImeController,
                 dragAndDropController,
@@ -182,6 +184,7 @@
                 legacySplitScreenOptional,
                 appPairsOptional,
                 fullscreenTaskListener,
+                transitions,
                 shellMainExecutor);
     }
 
@@ -342,6 +345,14 @@
 
     @WMSingleton
     @Provides
+    static Optional<TaskViewFactory> provideTaskViewFactory(ShellTaskOrganizer shellTaskOrganizer,
+            @ShellMainThread ShellExecutor mainExecutor) {
+        return Optional.of(new TaskViewFactoryController(shellTaskOrganizer, mainExecutor)
+                .getTaskViewFactory());
+    }
+
+    @WMSingleton
+    @Provides
     static FullscreenTaskListener provideFullscreenTaskListener(
             SyncTransactionQueue syncQueue) {
         return new FullscreenTaskListener(syncQueue);
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index 509419e..e635e17 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -17,13 +17,10 @@
 package com.android.systemui.wmshell;
 
 import android.content.Context;
-import android.os.Handler;
 import android.view.IWindowManager;
 
 import com.android.systemui.dagger.WMSingleton;
-import com.android.systemui.dagger.qualifiers.Main;
 import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.Transitions;
 import com.android.wm.shell.WindowManagerShellWrapper;
 import com.android.wm.shell.apppairs.AppPairs;
 import com.android.wm.shell.apppairs.AppPairsController;
@@ -49,9 +46,9 @@
 import com.android.wm.shell.pip.phone.PipAppOpsListener;
 import com.android.wm.shell.pip.phone.PipController;
 import com.android.wm.shell.pip.phone.PipTouchHandler;
+import com.android.wm.shell.transition.Transitions;
 
 import java.util.Optional;
-import java.util.concurrent.Executor;
 
 import dagger.Module;
 import dagger.Provides;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
index 6978ef4..4e4c33a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
@@ -37,13 +37,14 @@
 import android.view.animation.AccelerateInterpolator;
 
 import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.MediumTest;
+import androidx.test.filters.LargeTest;
 
 import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
 import com.android.systemui.SysuiTestCase;
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -54,7 +55,8 @@
 import java.util.concurrent.atomic.AtomicReference;
 
 
-@MediumTest
+@Ignore
+@LargeTest
 @RunWith(AndroidTestingRunner.class)
 public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
 
diff --git a/services/Android.bp b/services/Android.bp
index 3447b5c..da24719 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -30,6 +30,7 @@
         ":services.searchui-sources",
         ":services.startop.iorap-sources",
         ":services.systemcaptions-sources",
+        ":services.translation-sources",
         ":services.usage-sources",
         ":services.usb-sources",
         ":services.voiceinteraction-sources",
@@ -76,12 +77,12 @@
         "services.searchui",
         "services.startop",
         "services.systemcaptions",
+        "services.translation",
         "services.usage",
         "services.usb",
         "services.voiceinteraction",
         "services.wifi",
         "service-blobstore",
-        "service-connectivity",
         "service-jobscheduler",
         "android.hidl.base-V1.0-java",
     ],
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 8a27acc..9d02835 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -919,9 +919,10 @@
                     break;
 
                     case "associate": {
+                        int userId = getNextArgInt();
                         String pkg = getNextArgRequired();
                         String address = getNextArgRequired();
-                        addAssociation(new Association(getNextArgInt(), address, pkg, null, false));
+                        addAssociation(new Association(userId, address, pkg, null, false));
                     }
                     break;
 
diff --git a/services/core/java/android/power/OWNERS b/services/core/java/android/power/OWNERS
new file mode 100644
index 0000000..4068e2b
--- /dev/null
+++ b/services/core/java/android/power/OWNERS
@@ -0,0 +1 @@
+include /BATTERY_STATS_OWNERS
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 397eeb2..020c17a 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -620,7 +620,7 @@
     private LingerMonitor mLingerMonitor;
 
     // sequence number of NetworkRequests
-    private int mNextNetworkRequestId = 1;
+    private int mNextNetworkRequestId = NetworkRequest.FIRST_REQUEST_ID;
 
     // Sequence number for NetworkProvider IDs.
     private final AtomicInteger mNextNetworkProviderId = new AtomicInteger(
@@ -1238,6 +1238,8 @@
     }
 
     private synchronized int nextNetworkRequestId() {
+        // TODO: Consider handle wrapping and exclude {@link NetworkRequest#REQUEST_ID_NONE} if
+        //  doing that.
         return mNextNetworkRequestId++;
     }
 
@@ -1329,15 +1331,20 @@
     /**
      * Check if UID should be blocked from using the specified network.
      */
-    private boolean isNetworkWithLinkPropertiesBlocked(LinkProperties lp, int uid,
-            boolean ignoreBlocked) {
+    private boolean isNetworkWithCapabilitiesBlocked(@Nullable final NetworkCapabilities nc,
+            final int uid, final boolean ignoreBlocked) {
         // Networks aren't blocked when ignoring blocked status
         if (ignoreBlocked) {
             return false;
         }
         if (isUidBlockedByVpn(uid, mVpnBlockedUidRanges)) return true;
-        final String iface = (lp == null ? "" : lp.getInterfaceName());
-        return mPolicyManagerInternal.isUidNetworkingBlocked(uid, iface);
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            final boolean metered = nc == null ? true : nc.isMetered();
+            return mPolicyManager.isUidNetworkingBlocked(uid, metered);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
     }
 
     private void maybeLogBlockedNetworkInfo(NetworkInfo ni, int uid) {
@@ -1375,12 +1382,13 @@
     /**
      * Apply any relevant filters to {@link NetworkState} for the given UID. For
      * example, this may mark the network as {@link DetailedState#BLOCKED} based
-     * on {@link #isNetworkWithLinkPropertiesBlocked}.
+     * on {@link #isNetworkWithCapabilitiesBlocked}.
      */
     private void filterNetworkStateForUid(NetworkState state, int uid, boolean ignoreBlocked) {
         if (state == null || state.networkInfo == null || state.linkProperties == null) return;
 
-        if (isNetworkWithLinkPropertiesBlocked(state.linkProperties, uid, ignoreBlocked)) {
+        if (isNetworkWithCapabilitiesBlocked(state.networkCapabilities, uid,
+                ignoreBlocked)) {
             state.networkInfo.setDetailedState(DetailedState.BLOCKED, null, null);
         }
         synchronized (mVpns) {
@@ -1440,8 +1448,8 @@
             }
         }
         nai = getDefaultNetwork();
-        if (nai != null
-                && isNetworkWithLinkPropertiesBlocked(nai.linkProperties, uid, ignoreBlocked)) {
+        if (nai != null && isNetworkWithCapabilitiesBlocked(
+                nai.networkCapabilities, uid, ignoreBlocked)) {
             nai = null;
         }
         return nai != null ? nai.network : null;
@@ -1513,7 +1521,7 @@
         enforceAccessPermission();
         final int uid = mDeps.getCallingUid();
         NetworkState state = getFilteredNetworkState(networkType, uid);
-        if (!isNetworkWithLinkPropertiesBlocked(state.linkProperties, uid, false)) {
+        if (!isNetworkWithCapabilitiesBlocked(state.networkCapabilities, uid, false)) {
             return state.network;
         }
         return null;
@@ -4471,7 +4479,8 @@
         if (!nai.everConnected) {
             return;
         }
-        if (isNetworkWithLinkPropertiesBlocked(nai.linkProperties, uid, false)) {
+        final NetworkCapabilities nc = getNetworkCapabilitiesInternal(nai);
+        if (isNetworkWithCapabilitiesBlocked(nc, uid, false)) {
             return;
         }
         nai.networkMonitor().forceReevaluation(uid);
@@ -7065,11 +7074,11 @@
                     log("   accepting network in place of " + previousSatisfier.toShortString());
                 }
                 previousSatisfier.removeRequest(nri.request.requestId);
-                previousSatisfier.lingerRequest(nri.request, now, mLingerDelayMs);
+                previousSatisfier.lingerRequest(nri.request.requestId, now, mLingerDelayMs);
             } else {
                 if (VDBG || DDBG) log("   accepting network in place of null");
             }
-            newSatisfier.unlingerRequest(nri.request);
+            newSatisfier.unlingerRequest(nri.request.requestId);
             if (!newSatisfier.addRequest(nri.request)) {
                 Log.wtf(TAG, "BUG: " + newSatisfier.toShortString() + " already has "
                         + nri.request);
diff --git a/services/core/java/com/android/server/ConnectivityServiceInitializer.java b/services/core/java/com/android/server/ConnectivityServiceInitializer.java
index f701688..0779f71 100644
--- a/services/core/java/com/android/server/ConnectivityServiceInitializer.java
+++ b/services/core/java/com/android/server/ConnectivityServiceInitializer.java
@@ -35,6 +35,8 @@
 
     public ConnectivityServiceInitializer(Context context) {
         super(context);
+        // Load JNI libraries used by ConnectivityService and its dependencies
+        System.loadLibrary("service-connectivity");
         // TODO: Define formal APIs to get the needed services.
         mConnectivity = new ConnectivityService(context, getNetworkManagementService(),
                 getNetworkStatsService());
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index 99a1d86..8b506ba 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -54,9 +54,13 @@
 
 import org.xmlpull.v1.XmlPullParserException;
 
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.annotation.Retention;
@@ -149,6 +153,11 @@
     private static final String ATTR_PASSED_HEALTH_CHECK = "passed-health-check";
     private static final String ATTR_MITIGATION_CALLS = "mitigation-calls";
 
+    // A file containing information about the current mitigation count in the case of a boot loop.
+    // This allows boot loop information to persist in the case of an fs-checkpoint being
+    // aborted.
+    private static final String METADATA_FILE = "/metadata/watchdog/mitigation_count.txt";
+
     @GuardedBy("PackageWatchdog.class")
     private static PackageWatchdog sPackageWatchdog;
 
@@ -492,6 +501,7 @@
                 }
                 if (currentObserverToNotify != null) {
                     mBootThreshold.setMitigationCount(mitigationCount);
+                    mBootThreshold.saveMitigationCountToMetadata();
                     currentObserverToNotify.executeBootLoopMitigation(mitigationCount);
                 }
             }
@@ -1700,9 +1710,31 @@
             SystemProperties.set(property, Long.toString(newStart));
         }
 
+        public void saveMitigationCountToMetadata() {
+            try (BufferedWriter writer = new BufferedWriter(new FileWriter(METADATA_FILE))) {
+                writer.write(String.valueOf(getMitigationCount()));
+            } catch (Exception e) {
+                Slog.e(TAG, "Could not save metadata to file: " + e);
+            }
+        }
+
+        public void readMitigationCountFromMetadataIfNecessary() {
+            File bootPropsFile = new File(METADATA_FILE);
+            if (bootPropsFile.exists()) {
+                try (BufferedReader reader = new BufferedReader(new FileReader(METADATA_FILE))) {
+                    String mitigationCount = reader.readLine();
+                    setMitigationCount(Integer.parseInt(mitigationCount));
+                    bootPropsFile.delete();
+                } catch (Exception e) {
+                    Slog.i(TAG, "Could not read metadata file: " + e);
+                }
+            }
+        }
+
 
         /** Increments the boot counter, and returns whether the device is bootlooping. */
         public boolean incrementAndTest() {
+            readMitigationCountFromMetadataIfNecessary();
             final long now = mSystemClock.uptimeMillis();
             if (now - getStart() < 0) {
                 Slog.e(TAG, "Window was less than zero. Resetting start to current time.");
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index a1cf816..db36e62 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -31,6 +31,7 @@
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.FileUtils;
+import android.os.PowerManager;
 import android.os.RecoverySystem;
 import android.os.RemoteCallback;
 import android.os.SystemClock;
@@ -77,6 +78,7 @@
     @VisibleForTesting
     static final String PROP_ENABLE_RESCUE = "persist.sys.enable_rescue";
     static final String PROP_ATTEMPTING_FACTORY_RESET = "sys.attempting_factory_reset";
+    static final String PROP_ATTEMPTING_REBOOT = "sys.attempting_reboot";
     static final String PROP_MAX_RESCUE_LEVEL_ATTEMPTED = "sys.max_rescue_level_attempted";
     @VisibleForTesting
     static final int LEVEL_NONE = 0;
@@ -87,7 +89,9 @@
     @VisibleForTesting
     static final int LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS = 3;
     @VisibleForTesting
-    static final int LEVEL_FACTORY_RESET = 4;
+    static final int LEVEL_WARM_REBOOT = 4;
+    @VisibleForTesting
+    static final int LEVEL_FACTORY_RESET = 5;
     @VisibleForTesting
     static final String PROP_RESCUE_BOOT_COUNT = "sys.rescue_boot_count";
     @VisibleForTesting
@@ -159,12 +163,24 @@
     }
 
     /**
-     * Check if we're currently attempting to reboot for a factory reset.
+     * Check if we're currently attempting to reboot for a factory reset. This method must
+     * return true if RescueParty tries to reboot early during a boot loop, since the device
+     * will not be fully booted at this time.
+     *
+     * TODO(gavincorkery): Rename method since its scope has expanded.
      */
     public static boolean isAttemptingFactoryReset() {
+        return isFactoryResetPropertySet() || isRebootPropertySet();
+    }
+
+    static boolean isFactoryResetPropertySet() {
         return SystemProperties.getBoolean(PROP_ATTEMPTING_FACTORY_RESET, false);
     }
 
+    static boolean isRebootPropertySet() {
+        return SystemProperties.getBoolean(PROP_ATTEMPTING_REBOOT, false);
+    }
+
     /**
      * Called when {@code SettingsProvider} has been published, which is a good
      * opportunity to reset any settings depending on our rescue level.
@@ -329,8 +345,10 @@
             return LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES;
         } else if (mitigationCount == 3) {
             return LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS;
-        } else if (mitigationCount >= 4) {
-            return getMaxRescueLevel();
+        } else if (mitigationCount == 4) {
+            return Math.min(getMaxRescueLevel(), LEVEL_WARM_REBOOT);
+        } else if (mitigationCount >= 5) {
+            return Math.min(getMaxRescueLevel(), LEVEL_FACTORY_RESET);
         } else {
             Slog.w(TAG, "Expected positive mitigation count, was " + mitigationCount);
             return LEVEL_NONE;
@@ -356,6 +374,8 @@
         // Try our best to reset all settings possible, and once finished
         // rethrow any exception that we encountered
         Exception res = null;
+        Runnable runnable;
+        Thread thread;
         switch (level) {
             case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
                 try {
@@ -396,11 +416,26 @@
                     res = e;
                 }
                 break;
-            case LEVEL_FACTORY_RESET:
+            case LEVEL_WARM_REBOOT:
                 // Request the reboot from a separate thread to avoid deadlock on PackageWatchdog
                 // when device shutting down.
+                SystemProperties.set(PROP_ATTEMPTING_REBOOT, "true");
+                runnable = () -> {
+                    try {
+                        PowerManager pm = context.getSystemService(PowerManager.class);
+                        if (pm != null) {
+                            pm.reboot(TAG);
+                        }
+                    } catch (Throwable t) {
+                        logRescueException(level, t);
+                    }
+                };
+                thread = new Thread(runnable);
+                thread.start();
+                break;
+            case LEVEL_FACTORY_RESET:
                 SystemProperties.set(PROP_ATTEMPTING_FACTORY_RESET, "true");
-                Runnable runnable = new Runnable() {
+                runnable = new Runnable() {
                     @Override
                     public void run() {
                         try {
@@ -410,7 +445,7 @@
                         }
                     }
                 };
-                Thread thread = new Thread(runnable);
+                thread = new Thread(runnable);
                 thread.start();
                 break;
         }
@@ -433,6 +468,7 @@
             case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
                 return PackageHealthObserverImpact.USER_IMPACT_LOW;
             case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
+            case LEVEL_WARM_REBOOT:
             case LEVEL_FACTORY_RESET:
                 return PackageHealthObserverImpact.USER_IMPACT_HIGH;
             default:
@@ -714,6 +750,7 @@
             case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS: return "RESET_SETTINGS_UNTRUSTED_DEFAULTS";
             case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES: return "RESET_SETTINGS_UNTRUSTED_CHANGES";
             case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS: return "RESET_SETTINGS_TRUSTED_DEFAULTS";
+            case LEVEL_WARM_REBOOT: return "WARM_REBOOT";
             case LEVEL_FACTORY_RESET: return "FACTORY_RESET";
             default: return Integer.toString(level);
         }
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index b0f2e24..c951fd4 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -1716,7 +1716,7 @@
     public StorageManagerService(Context context) {
         sSelf = this;
         mVoldAppDataIsolationEnabled = SystemProperties.getBoolean(
-                ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, true);
+                ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false);
         mContext = context;
         mResolver = mContext.getContentResolver();
         mCallbacks = new Callbacks(FgThread.get().getLooper());
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 0cbf4ba..c1ab5b6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -174,6 +174,7 @@
 import android.app.WaitResult;
 import android.app.backup.BackupManager.OperationType;
 import android.app.backup.IBackupManager;
+import android.app.compat.CompatChanges;
 import android.app.usage.UsageEvents;
 import android.app.usage.UsageEvents.Event;
 import android.app.usage.UsageStatsManager;
@@ -13706,10 +13707,34 @@
                             false, false, userId, "package unstartable");
                     break;
                 case Intent.ACTION_CLOSE_SYSTEM_DIALOGS:
-                    if (!mAtmInternal.checkCanCloseSystemDialogs(callingPid, callingUid,
-                            callerPackage)) {
-                        // Returning success seems to be the pattern here
-                        return ActivityManager.BROADCAST_SUCCESS;
+                    if (!canCloseSystemDialogs(callingPid, callingUid, callerApp)) {
+                        // The app can't close system dialogs, throw only if it targets S+
+                        if (CompatChanges.isChangeEnabled(
+                                ActivityManager.LOCK_DOWN_CLOSE_SYSTEM_DIALOGS, callingUid)) {
+                            throw new SecurityException(
+                                    "Permission Denial: " + Intent.ACTION_CLOSE_SYSTEM_DIALOGS
+                                            + " broadcast from " + callerPackage + " (pid="
+                                            + callingPid + ", uid=" + callingUid + ")"
+                                            + " requires "
+                                            + permission.BROADCAST_CLOSE_SYSTEM_DIALOGS + ".");
+                        } else if (CompatChanges.isChangeEnabled(
+                                ActivityManager.DROP_CLOSE_SYSTEM_DIALOGS, callingUid)) {
+                            Slog.w(TAG, "Permission Denial: " + intent.getAction()
+                                    + " broadcast from " + callerPackage + " (pid=" + callingPid
+                                    + ", uid=" + callingUid + ")"
+                                    + " requires "
+                                    + permission.BROADCAST_CLOSE_SYSTEM_DIALOGS
+                                    + ", dropping broadcast.");
+                            // Returning success seems to be the pattern here
+                            return ActivityManager.BROADCAST_SUCCESS;
+                        } else {
+                            Slog.w(TAG, intent.getAction()
+                                    + " broadcast from " + callerPackage + " (pid=" + callingPid
+                                    + ", uid=" + callingUid + ")"
+                                    + " will require  "
+                                    + permission.BROADCAST_CLOSE_SYSTEM_DIALOGS
+                                    + " in future builds.");
+                        }
                     }
                     break;
             }
@@ -14004,6 +14029,39 @@
         return ActivityManager.BROADCAST_SUCCESS;
     }
 
+    private boolean canCloseSystemDialogs(int pid, int uid, @Nullable ProcessRecord callerApp) {
+        if (checkPermission(permission.BROADCAST_CLOSE_SYSTEM_DIALOGS, pid, uid)
+                == PERMISSION_GRANTED) {
+            return true;
+        }
+        if (callerApp == null) {
+            synchronized (mPidsSelfLocked) {
+                callerApp = mPidsSelfLocked.get(pid);
+            }
+        }
+
+        if (callerApp != null) {
+            // Check if the instrumentation of the process has the permission. This covers the usual
+            // test started from the shell (which has the permission) case. This is needed for apps
+            // targeting SDK level < S but we are also allowing for targetSdk S+ as a convenience to
+            // avoid breaking a bunch of existing tests and asking them to adopt shell permissions
+            // to do this.
+            ActiveInstrumentation instrumentation = callerApp.getActiveInstrumentation();
+            if (instrumentation != null && checkPermission(
+                    permission.BROADCAST_CLOSE_SYSTEM_DIALOGS, -1, instrumentation.mSourceUid)
+                    == PERMISSION_GRANTED) {
+                return true;
+            }
+            // This is the notification trampoline use-case for example, where apps use Intent.ACSD
+            // to close the shade prior to starting an activity.
+            WindowProcessController wmApp = callerApp.getWindowProcessController();
+            if (wmApp.canCloseSystemDialogsByToken()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * @return uid from the extra field {@link Intent#EXTRA_UID} if present, Otherwise -1
      */
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 53d75d1..6f6cad0 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -711,7 +711,7 @@
         mAppDataIsolationEnabled =
                 SystemProperties.getBoolean(ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY, true);
         mVoldAppDataIsolationEnabled = SystemProperties.getBoolean(
-                ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, true);
+                ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false);
         mAppDataIsolationWhitelistedApps = new ArrayList<>(
                 SystemConfig.getInstance().getAppDataIsolationWhitelistedApps());
 
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 669d04a..e90423c 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -1431,9 +1431,7 @@
     void setActiveInstrumentation(ActiveInstrumentation instr) {
         mInstr = instr;
         boolean isInstrumenting = instr != null;
-        mWindowProcessController.setInstrumenting(
-                isInstrumenting,
-                isInstrumenting ? instr.mSourceUid : -1,
+        mWindowProcessController.setInstrumenting(isInstrumenting,
                 isInstrumenting && instr.mHasBackgroundActivityStartsPermission);
     }
 
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationConstants.java b/services/core/java/com/android/server/apphibernation/AppHibernationConstants.java
new file mode 100644
index 0000000..9d43a39
--- /dev/null
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationConstants.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.apphibernation;
+
+/**
+ * Flags and constants that modify app hibernation behavior.
+ */
+final class AppHibernationConstants {
+
+    private AppHibernationConstants() {}
+
+    // Device config feature flag for app hibernation
+    static final String KEY_APP_HIBERNATION_ENABLED = "app_hibernation_enabled";
+}
diff --git a/services/core/java/com/android/server/apphibernation/OWNERS b/services/core/java/com/android/server/apphibernation/OWNERS
index 4804fa3..c2e27e0 100644
--- a/services/core/java/com/android/server/apphibernation/OWNERS
+++ b/services/core/java/com/android/server/apphibernation/OWNERS
@@ -1,3 +1 @@
-# TODO: Include /core/java/android/apphibernation/OWNERS. See b/177005153
-kevhan@google.com
-rajekumar@google.com
+include /core/java/android/apphibernation/OWNERS
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 b8084d5..fe946cb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/InvalidationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/InvalidationClient.java
@@ -21,6 +21,8 @@
 import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.BiometricsProtoEnums;
 
+import java.util.Map;
+
 /**
  * ClientMonitor subclass for requesting authenticatorId invalidation. See
  * {@link InvalidationRequesterClient} for more info.
@@ -29,18 +31,21 @@
         extends ClientMonitor<T> {
 
     private final BiometricUtils<S> mUtils;
+    private final Map<Integer, Long> mAuthenticatorIds;
 
     public InvalidationClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
-            int userId, int sensorId, @NonNull BiometricUtils<S> utils) {
+            int userId, int sensorId, @NonNull BiometricUtils<S> utils,
+            @NonNull Map<Integer, Long> authenticatorIds) {
         super(context, lazyDaemon, null /* token */, null /* listener */, userId,
                 context.getOpPackageName(), 0 /* cookie */, sensorId,
                 BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN,
                 BiometricsProtoEnums.CLIENT_UNKNOWN);
         mUtils = utils;
+        mAuthenticatorIds = authenticatorIds;
     }
 
     public void onAuthenticatorIdInvalidated(long newAuthenticatorId) {
-        // TODO: Update framework w/ newAuthenticatorId
+        mAuthenticatorIds.put(getTargetUserId(), newAuthenticatorId);
         mCallback.onClientFinished(this, true /* success */);
     }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInvalidationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInvalidationClient.java
index f512cef..9c6438e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInvalidationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInvalidationClient.java
@@ -16,10 +16,9 @@
 
 package com.android.server.biometrics.sensors.face.aidl;
 
+import android.annotation.NonNull;
 import android.content.Context;
 import android.hardware.biometrics.face.ISession;
-
-import android.annotation.NonNull;
 import android.hardware.face.Face;
 import android.os.RemoteException;
 import android.util.Slog;
@@ -27,13 +26,15 @@
 import com.android.server.biometrics.sensors.InvalidationClient;
 import com.android.server.biometrics.sensors.face.FaceUtils;
 
+import java.util.Map;
+
 public class FaceInvalidationClient extends InvalidationClient<Face, ISession> {
     private static final String TAG = "FaceInvalidationClient";
 
     public FaceInvalidationClient(@NonNull Context context,
             @NonNull LazyDaemon<ISession> lazyDaemon, int userId, int sensorId,
-            @NonNull FaceUtils utils) {
-        super(context, lazyDaemon, userId, sensorId, utils);
+            @NonNull FaceUtils utils, @NonNull Map<Integer, Long> authenticatorIds) {
+        super(context, lazyDaemon, userId, sensorId, utils, authenticatorIds);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInvalidationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInvalidationClient.java
index b6d8892..3d07334 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInvalidationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInvalidationClient.java
@@ -26,13 +26,15 @@
 import com.android.server.biometrics.sensors.InvalidationClient;
 import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
 
+import java.util.Map;
+
 public class FingerprintInvalidationClient extends InvalidationClient<Fingerprint, ISession> {
     private static final String TAG = "FingerprintInvalidationClient";
 
     public FingerprintInvalidationClient(@NonNull Context context,
             @NonNull LazyDaemon<ISession> lazyDaemon, int userId, int sensorId,
-            @NonNull FingerprintUtils utils) {
-        super(context, lazyDaemon, userId, sensorId, utils);
+            @NonNull FingerprintUtils utils, @NonNull Map<Integer, Long> authenticatorIds) {
+        super(context, lazyDaemon, userId, sensorId, utils, authenticatorIds);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
index 2c06d82..b5d875d 100644
--- a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
@@ -122,6 +122,8 @@
 
     public IpConnectivityMetrics(Context ctx, ToIntFunction<Context> capacityGetter) {
         super(ctx);
+        // Load JNI libraries used by the IpConnectivityMetrics service and its dependencies
+        System.loadLibrary("service-connectivity");
         mCapacityGetter = capacityGetter;
         initBuffer();
     }
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 7bde4d5..55d8279 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -202,28 +202,28 @@
     // either the linger timeout expiring and the network being taken down, or the network
     // satisfying a request again.
     public static class LingerTimer implements Comparable<LingerTimer> {
-        public final NetworkRequest request;
+        public final int requestId;
         public final long expiryMs;
 
-        public LingerTimer(NetworkRequest request, long expiryMs) {
-            this.request = request;
+        public LingerTimer(int requestId, long expiryMs) {
+            this.requestId = requestId;
             this.expiryMs = expiryMs;
         }
         public boolean equals(Object o) {
             if (!(o instanceof LingerTimer)) return false;
             LingerTimer other = (LingerTimer) o;
-            return (request.requestId == other.request.requestId) && (expiryMs == other.expiryMs);
+            return (requestId == other.requestId) && (expiryMs == other.expiryMs);
         }
         public int hashCode() {
-            return Objects.hash(request.requestId, expiryMs);
+            return Objects.hash(requestId, expiryMs);
         }
         public int compareTo(LingerTimer other) {
             return (expiryMs != other.expiryMs) ?
                     Long.compare(expiryMs, other.expiryMs) :
-                    Integer.compare(request.requestId, other.request.requestId);
+                    Integer.compare(requestId, other.requestId);
         }
         public String toString() {
-            return String.format("%s, expires %dms", request.toString(),
+            return String.format("%s, expires %dms", requestId,
                     expiryMs - SystemClock.elapsedRealtime());
         }
     }
@@ -693,7 +693,7 @@
         updateRequestCounts(REMOVE, existing);
         mNetworkRequests.remove(requestId);
         if (existing.isRequest()) {
-            unlingerRequest(existing);
+            unlingerRequest(existing.requestId);
         }
     }
 
@@ -839,33 +839,33 @@
     }
 
     /**
-     * Sets the specified request to linger on this network for the specified time. Called by
+     * Sets the specified requestId to linger on this network for the specified time. Called by
      * ConnectivityService when the request is moved to another network with a higher score.
      */
-    public void lingerRequest(NetworkRequest request, long now, long duration) {
-        if (mLingerTimerForRequest.get(request.requestId) != null) {
+    public void lingerRequest(int requestId, long now, long duration) {
+        if (mLingerTimerForRequest.get(requestId) != null) {
             // Cannot happen. Once a request is lingering on a particular network, we cannot
             // re-linger it unless that network becomes the best for that request again, in which
             // case we should have unlingered it.
-            Log.wtf(TAG, toShortString() + ": request " + request.requestId + " already lingered");
+            Log.wtf(TAG, toShortString() + ": request " + requestId + " already lingered");
         }
         final long expiryMs = now + duration;
-        LingerTimer timer = new LingerTimer(request, expiryMs);
+        LingerTimer timer = new LingerTimer(requestId, expiryMs);
         if (VDBG) Log.d(TAG, "Adding LingerTimer " + timer + " to " + toShortString());
         mLingerTimers.add(timer);
-        mLingerTimerForRequest.put(request.requestId, timer);
+        mLingerTimerForRequest.put(requestId, timer);
     }
 
     /**
      * Cancel lingering. Called by ConnectivityService when a request is added to this network.
-     * Returns true if the given request was lingering on this network, false otherwise.
+     * Returns true if the given requestId was lingering on this network, false otherwise.
      */
-    public boolean unlingerRequest(NetworkRequest request) {
-        LingerTimer timer = mLingerTimerForRequest.get(request.requestId);
+    public boolean unlingerRequest(int requestId) {
+        LingerTimer timer = mLingerTimerForRequest.get(requestId);
         if (timer != null) {
             if (VDBG) Log.d(TAG, "Removing LingerTimer " + timer + " from " + toShortString());
             mLingerTimers.remove(timer);
-            mLingerTimerForRequest.remove(request.requestId);
+            mLingerTimerForRequest.remove(requestId);
             return true;
         }
         return false;
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index 06721ae..93930ae 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -177,7 +177,7 @@
      * @param proxy Proxy information that is about to be broadcast.
      * @return Returns whether the broadcast should be sent : either DO_ or DONT_SEND_BROADCAST
      */
-    synchronized boolean setCurrentProxyScriptUrl(ProxyInfo proxy) {
+    public synchronized boolean setCurrentProxyScriptUrl(ProxyInfo proxy) {
         if (!Uri.EMPTY.equals(proxy.getPacFileUrl())) {
             if (proxy.getPacFileUrl().equals(mPacUrl) && (proxy.getPort() > 0)) {
                 // Allow to send broadcast, nothing to do.
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 07a4b89..b250f16 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -1850,34 +1850,6 @@
         }
     }
 
-    /**
-     * @param uid The target uid.
-     *
-     * @return {@code true} if {@code uid} is included in one of the mBlockedUidsAsToldToNetd
-     * ranges and the VPN is not connected, or if the VPN is connected but does not apply to
-     * the {@code uid}.
-     *
-     * @apiNote This method don't check VPN lockdown status.
-     * @see #mBlockedUidsAsToldToConnectivity
-     */
-    public synchronized boolean isBlockingUid(int uid) {
-        if (mNetworkInfo.isConnected()) {
-            return !appliesToUid(uid);
-        } else {
-            return containsUid(mBlockedUidsAsToldToConnectivity, uid);
-        }
-    }
-
-    private boolean containsUid(Collection<UidRangeParcel> ranges, int uid) {
-        if (ranges == null) return false;
-        for (UidRangeParcel range : ranges) {
-            if (range.start <= uid && uid <= range.stop) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     private void updateAlwaysOnNotification(DetailedState networkState) {
         final boolean visible = (mAlwaysOn && networkState != DetailedState.CONNECTED);
 
diff --git a/services/core/java/com/android/server/graphics/fonts/OWNERS b/services/core/java/com/android/server/graphics/fonts/OWNERS
new file mode 100644
index 0000000..34ac813
--- /dev/null
+++ b/services/core/java/com/android/server/graphics/fonts/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 24939
+
+include /graphics/java/android/graphics/fonts/OWNERS
diff --git a/services/core/java/com/android/server/location/timezone/ControllerImpl.java b/services/core/java/com/android/server/location/timezone/ControllerImpl.java
index 2b3c0bf..0d284fc 100644
--- a/services/core/java/com/android/server/location/timezone/ControllerImpl.java
+++ b/services/core/java/com/android/server/location/timezone/ControllerImpl.java
@@ -73,6 +73,10 @@
     // Non-null after initialize()
     private Callback mCallback;
 
+    /** Indicates both providers have completed initialization. */
+    @GuardedBy("mSharedLock")
+    private boolean mProvidersInitialized;
+
     /**
      * Used for scheduling uncertainty timeouts, i.e after a provider has reported uncertainty.
      * This timeout is not provider-specific: it is started when the controller becomes uncertain
@@ -108,6 +112,7 @@
                     ControllerImpl.this::onProviderStateChange;
             mPrimaryProvider.initialize(providerListener);
             mSecondaryProvider.initialize(providerListener);
+            mProvidersInitialized = true;
 
             alterProvidersStartedStateIfRequired(
                     null /* oldConfiguration */, mCurrentUserConfiguration);
@@ -322,6 +327,16 @@
         assertProviderKnown(provider);
 
         synchronized (mSharedLock) {
+            // Ignore provider state changes during initialization. e.g. if the primary provider
+            // moves to PROVIDER_STATE_PERM_FAILED during initialization, the secondary will not
+            // be ready to take over yet.
+            if (!mProvidersInitialized) {
+                warnLog("onProviderStateChange: Ignoring provider state change because both"
+                        + " providers have not yet completed initialization."
+                        + " providerState=" + providerState);
+                return;
+            }
+
             switch (providerState.stateEnum) {
                 case PROVIDER_STATE_STARTED_INITIALIZING:
                 case PROVIDER_STATE_STOPPED:
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
index 407cedf..141fa6a 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
@@ -44,12 +44,6 @@
     public abstract boolean isUidRestrictedOnMeteredNetworks(int uid);
 
     /**
-     * @return true if networking is blocked on the given interface for the given uid according
-     * to current networking policies.
-     */
-    public abstract boolean isUidNetworkingBlocked(int uid, String ifname);
-
-    /**
      * Figure out if networking is blocked for a given set of conditions.
      *
      * This is used by ConnectivityService via passing stale copies of conditions, so it must not
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 0e7b4b8..7c17356 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -5352,7 +5352,7 @@
     public boolean isUidNetworkingBlocked(int uid, boolean isNetworkMetered) {
         final long startTime = mStatLogger.getTime();
 
-        mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
+        enforceAnyPermissionOf(OBSERVE_NETWORK_POLICY, PERMISSION_MAINLINE_NETWORK_STACK);
         final int uidRules;
         final boolean isBackgroundRestricted;
         synchronized (mUidRulesFirstLock) {
@@ -5451,32 +5451,6 @@
                     && !hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED);
         }
 
-        /**
-         * @return true if networking is blocked on the given interface for the given uid according
-         * to current networking policies.
-         */
-        @Override
-        public boolean isUidNetworkingBlocked(int uid, String ifname) {
-            final long startTime = mStatLogger.getTime();
-
-            final int uidRules;
-            final boolean isBackgroundRestricted;
-            synchronized (mUidRulesFirstLock) {
-                uidRules = mUidRules.get(uid, RULE_NONE);
-                isBackgroundRestricted = mRestrictBackground;
-            }
-            final boolean isNetworkMetered;
-            synchronized (mMeteredIfacesLock) {
-                isNetworkMetered = mMeteredIfaces.contains(ifname);
-            }
-            final boolean ret = isUidNetworkingBlockedInternal(uid, uidRules, isNetworkMetered,
-                    isBackgroundRestricted, mLogger);
-
-            mStatLogger.logDurationStat(Stats.IS_UID_NETWORKING_BLOCKED, startTime);
-
-            return ret;
-        }
-
         @Override
         public void onTempPowerSaveWhitelistChange(int appId, boolean added) {
             synchronized (mUidRulesFirstLock) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 5ac581a..4ab8279 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -446,16 +446,6 @@
     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
     private static final long NOTIFICATION_TRAMPOLINE_BLOCK = 167676448L;
 
-    /**
-     * Rate limit showing toasts, on a per package basis.
-     *
-     * It limits the effects of {@link android.widget.Toast#show()} calls to prevent overburdening
-     * the user with too many toasts in a limited time. Any attempt to show more toasts than allowed
-     * in a certain time frame will result in the toast being discarded.
-     */
-    @ChangeId
-    private static final long RATE_LIMIT_TOASTS = 154198299L;
-
     private IActivityManager mAm;
     private ActivityTaskManagerInternal mAtm;
     private ActivityManager mActivityManager;
@@ -527,6 +517,9 @@
     @GuardedBy("mNotificationLock")
     final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
     final ArrayList<ToastRecord> mToastQueue = new ArrayList<>();
+    // set of uids for which toast rate limiting is disabled
+    @GuardedBy("mToastQueue")
+    private final Set<Integer> mToastRateLimitingDisabledUids = new ArraySet<>();
     final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
 
     // True if the toast that's on top of the queue is being shown at the moment.
@@ -3068,6 +3061,22 @@
         }
 
         @Override
+        public void setToastRateLimitingEnabled(boolean enable) {
+            getContext().enforceCallingPermission(
+                    android.Manifest.permission.MANAGE_TOAST_RATE_LIMITING,
+                    "App doesn't have the permission to enable/disable toast rate limiting");
+
+            synchronized (mToastQueue) {
+                int uid = Binder.getCallingUid();
+                if (enable) {
+                    mToastRateLimitingDisabledUids.remove(uid);
+                } else {
+                    mToastRateLimitingDisabledUids.add(uid);
+                }
+            }
+        }
+
+        @Override
         public void finishToken(String pkg, IBinder token) {
             synchronized (mToastQueue) {
                 final long callingId = Binder.clearCallingIdentity();
@@ -7378,7 +7387,7 @@
         while (record != null) {
             int userId = UserHandle.getUserId(record.uid);
             boolean rateLimitingEnabled =
-                    CompatChanges.isChangeEnabled(RATE_LIMIT_TOASTS, record.uid);
+                    !mToastRateLimitingDisabledUids.contains(record.uid);
             boolean isWithinQuota =
                     mToastRateLimiter.isWithinQuota(userId, record.pkg, TOAST_QUOTA_TAG);
 
diff --git a/services/core/java/com/android/server/pm/MULTIUSER_AND_ENTERPRISE_OWNERS b/services/core/java/com/android/server/pm/MULTIUSER_AND_ENTERPRISE_OWNERS
new file mode 100644
index 0000000..48f6bf8
--- /dev/null
+++ b/services/core/java/com/android/server/pm/MULTIUSER_AND_ENTERPRISE_OWNERS
@@ -0,0 +1,7 @@
+# OWNERS of Multiuser related files related to Enterprise
+
+# TODO: include /MULTIUSER_OWNERS
+
+# Enterprise owners
+rubinxu@google.com
+sandness@google.com
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 004c015..8f42289 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -4463,12 +4463,10 @@
 
         final PermissionPolicyInternal permissionPolicyInternal = LocalServices.getService(
                 PermissionPolicyInternal.class);
-        permissionPolicyInternal.setOnInitializedCallback(userId -> {
-            // The SDK updated case is already handled when we run during the ctor.
-            synchronized (mLock) {
-                updateAllPermissions(StorageManager.UUID_PRIVATE_INTERNAL, false);
-            }
-        });
+        permissionPolicyInternal.setOnInitializedCallback(userId ->
+                // The SDK updated case is already handled when we run during the ctor.
+                updateAllPermissions(StorageManager.UUID_PRIVATE_INTERNAL, false)
+        );
 
         mSystemReady = true;
 
diff --git a/services/core/java/com/android/server/powerstats/BatteryTrigger.java b/services/core/java/com/android/server/powerstats/BatteryTrigger.java
index 6500523..b35cb52 100644
--- a/services/core/java/com/android/server/powerstats/BatteryTrigger.java
+++ b/services/core/java/com/android/server/powerstats/BatteryTrigger.java
@@ -43,7 +43,7 @@
 
                     if (newBatteryLevel < mBatteryLevel) {
                         if (DEBUG) Slog.d(TAG, "Battery level dropped.  Log rail data");
-                        logPowerStatsData();
+                        logPowerStatsData(PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE_BATTERY_DROP);
                     }
 
                     mBatteryLevel = newBatteryLevel;
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java b/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java
index c9595c2..6d9cb75 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java
@@ -218,7 +218,7 @@
      *             array and written to on-device storage.
      */
     public void write(byte[] data) {
-        if (data.length > 0) {
+        if (data != null && data.length > 0) {
             mLock.lock();
 
             long currentTimeMillis = System.currentTimeMillis();
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsLogTrigger.java b/services/core/java/com/android/server/powerstats/PowerStatsLogTrigger.java
index 1754185..e3672a8 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsLogTrigger.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsLogTrigger.java
@@ -31,10 +31,8 @@
     protected Context mContext;
     private PowerStatsLogger mPowerStatsLogger;
 
-    protected void logPowerStatsData() {
-        Message.obtain(
-            mPowerStatsLogger,
-            PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE).sendToTarget();
+    protected void logPowerStatsData(int msgType) {
+        Message.obtain(mPowerStatsLogger, msgType).sendToTarget();
     }
 
     public PowerStatsLogTrigger(Context context, PowerStatsLogger powerStatsLogger) {
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsLogger.java b/services/core/java/com/android/server/powerstats/PowerStatsLogger.java
index 409cd82..9ee3429 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsLogger.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsLogger.java
@@ -20,6 +20,8 @@
 import android.hardware.power.stats.ChannelInfo;
 import android.hardware.power.stats.EnergyConsumerResult;
 import android.hardware.power.stats.EnergyMeasurement;
+import android.hardware.power.stats.PowerEntityInfo;
+import android.hardware.power.stats.StateResidencyResult;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -32,6 +34,8 @@
 import com.android.server.powerstats.ProtoStreamUtils.EnergyConsumerIdUtils;
 import com.android.server.powerstats.ProtoStreamUtils.EnergyConsumerResultUtils;
 import com.android.server.powerstats.ProtoStreamUtils.EnergyMeasurementUtils;
+import com.android.server.powerstats.ProtoStreamUtils.PowerEntityInfoUtils;
+import com.android.server.powerstats.ProtoStreamUtils.StateResidencyResultUtils;
 
 import java.io.ByteArrayInputStream;
 import java.io.File;
@@ -42,23 +46,25 @@
  * PowerStatsLogger is responsible for logging model and meter energy data to on-device storage.
  * Messages are sent to its message handler to request that energy data be logged, at which time it
  * queries the PowerStats HAL and logs the data to on-device storage.  The on-device storage is
- * dumped to file by calling writeModelDataToFile or writeMeterDataToFile with a file descriptor
- * that points to the output file.
+ * dumped to file by calling writeModelDataToFile, writeMeterDataToFile, or writeResidencyDataToFile
+ * with a file descriptor that points to the output file.
  */
 public final class PowerStatsLogger extends Handler {
     private static final String TAG = PowerStatsLogger.class.getSimpleName();
     private static final boolean DEBUG = false;
-    protected static final int MSG_LOG_TO_DATA_STORAGE = 0;
+    protected static final int MSG_LOG_TO_DATA_STORAGE_TIMER = 0;
+    protected static final int MSG_LOG_TO_DATA_STORAGE_BATTERY_DROP = 1;
 
     private final PowerStatsDataStorage mPowerStatsMeterStorage;
     private final PowerStatsDataStorage mPowerStatsModelStorage;
+    private final PowerStatsDataStorage mPowerStatsResidencyStorage;
     private final IPowerStatsHALWrapper mPowerStatsHALWrapper;
 
     @Override
     public void handleMessage(Message msg) {
         switch (msg.what) {
-            case MSG_LOG_TO_DATA_STORAGE:
-                if (DEBUG) Slog.d(TAG, "Logging to data storage");
+            case MSG_LOG_TO_DATA_STORAGE_TIMER:
+                if (DEBUG) Slog.d(TAG, "Logging to data storage on timer");
 
                 // Log power meter data.
                 EnergyMeasurement[] energyMeasurements =
@@ -74,6 +80,17 @@
                         EnergyConsumerResultUtils.getProtoBytes(energyConsumerResults));
                 if (DEBUG) EnergyConsumerResultUtils.print(energyConsumerResults);
                 break;
+
+            case MSG_LOG_TO_DATA_STORAGE_BATTERY_DROP:
+                if (DEBUG) Slog.d(TAG, "Logging to data storage on battery drop");
+
+                // Log state residency data.
+                StateResidencyResult[] stateResidencyResults =
+                    mPowerStatsHALWrapper.getStateResidency(new int[0]);
+                mPowerStatsResidencyStorage.write(
+                        StateResidencyResultUtils.getProtoBytes(stateResidencyResults));
+                if (DEBUG) StateResidencyResultUtils.print(stateResidencyResults);
+                break;
         }
     }
 
@@ -159,13 +176,57 @@
         pos.flush();
     }
 
+    /**
+     * Writes residency data stored in PowerStatsDataStorage to a file descriptor.
+     *
+     * @param fd FileDescriptor where residency data stored in PowerStatsDataStorage is written.
+     *           Data is written in protobuf format as defined by powerstatsservice.proto.
+     */
+    public void writeResidencyDataToFile(FileDescriptor fd) {
+        if (DEBUG) Slog.d(TAG, "Writing residency data to file");
+
+        final ProtoOutputStream pos = new ProtoOutputStream(fd);
+
+        try {
+            PowerEntityInfo[] powerEntityInfo = mPowerStatsHALWrapper.getPowerEntityInfo();
+            PowerEntityInfoUtils.packProtoMessage(powerEntityInfo, pos);
+            if (DEBUG) PowerEntityInfoUtils.print(powerEntityInfo);
+
+            mPowerStatsResidencyStorage.read(new PowerStatsDataStorage.DataElementReadCallback() {
+                @Override
+                public void onReadDataElement(byte[] data) {
+                    try {
+                        final ProtoInputStream pis =
+                                new ProtoInputStream(new ByteArrayInputStream(data));
+                        // TODO(b/166535853): ProtoOutputStream doesn't provide a method to write
+                        // a byte array that already contains a serialized proto, so I have to
+                        // deserialize, then re-serialize.  This is computationally inefficient.
+                        StateResidencyResult[] stateResidencyResult =
+                            StateResidencyResultUtils.unpackProtoMessage(data);
+                        StateResidencyResultUtils.packProtoMessage(stateResidencyResult, pos);
+                        if (DEBUG) StateResidencyResultUtils.print(stateResidencyResult);
+                    } catch (IOException e) {
+                        Slog.e(TAG, "Failed to write residency data to incident report.");
+                    }
+                }
+            });
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to write residency data to incident report.");
+        }
+
+        pos.flush();
+    }
+
     public PowerStatsLogger(Context context, File dataStoragePath, String meterFilename,
-            String modelFilename, IPowerStatsHALWrapper powerStatsHALWrapper) {
+            String modelFilename, String residencyFilename,
+            IPowerStatsHALWrapper powerStatsHALWrapper) {
         super(Looper.getMainLooper());
         mPowerStatsHALWrapper = powerStatsHALWrapper;
         mPowerStatsMeterStorage = new PowerStatsDataStorage(context, dataStoragePath,
             meterFilename);
         mPowerStatsModelStorage = new PowerStatsDataStorage(context, dataStoragePath,
             modelFilename);
+        mPowerStatsResidencyStorage = new PowerStatsDataStorage(context, dataStoragePath,
+            residencyFilename);
     }
 }
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsService.java b/services/core/java/com/android/server/powerstats/PowerStatsService.java
index ce50e583..7778572 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsService.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsService.java
@@ -49,6 +49,8 @@
     private static final int DATA_STORAGE_VERSION = 0;
     private static final String METER_FILENAME = "log.powerstats.meter." + DATA_STORAGE_VERSION;
     private static final String MODEL_FILENAME = "log.powerstats.model." + DATA_STORAGE_VERSION;
+    private static final String RESIDENCY_FILENAME =
+            "log.powerstats.residency." + DATA_STORAGE_VERSION;
 
     private final Injector mInjector;
 
@@ -76,15 +78,19 @@
             return MODEL_FILENAME;
         }
 
+        String createResidencyFilename() {
+            return RESIDENCY_FILENAME;
+        }
+
         IPowerStatsHALWrapper createPowerStatsHALWrapperImpl() {
             return PowerStatsHALWrapper.getPowerStatsHalImpl();
         }
 
         PowerStatsLogger createPowerStatsLogger(Context context, File dataStoragePath,
-                String meterFilename, String modelFilename,
+                String meterFilename, String modelFilename, String residencyFilename,
                 IPowerStatsHALWrapper powerStatsHALWrapper) {
             return new PowerStatsLogger(context, dataStoragePath, meterFilename,
-                modelFilename, powerStatsHALWrapper);
+                modelFilename, residencyFilename, powerStatsHALWrapper);
         }
 
         BatteryTrigger createBatteryTrigger(Context context, PowerStatsLogger powerStatsLogger) {
@@ -109,6 +115,8 @@
                         mPowerStatsLogger.writeModelDataToFile(fd);
                     } else if ("meter".equals(args[1])) {
                         mPowerStatsLogger.writeMeterDataToFile(fd);
+                    } else if ("residency".equals(args[1])) {
+                        mPowerStatsLogger.writeResidencyDataToFile(fd);
                     }
                 } else if (args.length == 0) {
                     pw.println("PowerStatsService dumpsys: available PowerEntityInfos");
@@ -148,7 +156,8 @@
             // Only start logger and triggers if initialization is successful.
             mPowerStatsLogger = mInjector.createPowerStatsLogger(mContext,
                 mInjector.createDataStoragePath(), mInjector.createMeterFilename(),
-                mInjector.createModelFilename(), mPowerStatsHALWrapper);
+                mInjector.createModelFilename(), mInjector.createResidencyFilename(),
+                mPowerStatsHALWrapper);
             mBatteryTrigger = mInjector.createBatteryTrigger(mContext, mPowerStatsLogger);
             mTimerTrigger = mInjector.createTimerTrigger(mContext, mPowerStatsLogger);
         } else {
diff --git a/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java b/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
index 5e23b86..ab9b3e0 100644
--- a/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
+++ b/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
@@ -20,6 +20,8 @@
 import android.hardware.power.stats.EnergyConsumerResult;
 import android.hardware.power.stats.EnergyMeasurement;
 import android.hardware.power.stats.PowerEntityInfo;
+import android.hardware.power.stats.StateInfo;
+import android.hardware.power.stats.StateResidency;
 import android.hardware.power.stats.StateResidencyResult;
 import android.util.Slog;
 import android.util.proto.ProtoInputStream;
@@ -45,6 +47,29 @@
     private static final String TAG = ProtoStreamUtils.class.getSimpleName();
 
     static class PowerEntityInfoUtils {
+        public static void packProtoMessage(PowerEntityInfo[] powerEntityInfo,
+                ProtoOutputStream pos) {
+            if (powerEntityInfo == null) return;
+
+            for (int i = 0; i < powerEntityInfo.length; i++) {
+                long peiToken = pos.start(PowerStatsServiceResidencyProto.POWER_ENTITY_INFO);
+                pos.write(PowerEntityInfoProto.POWER_ENTITY_ID, powerEntityInfo[i].powerEntityId);
+                pos.write(PowerEntityInfoProto.POWER_ENTITY_NAME,
+                        powerEntityInfo[i].powerEntityName);
+                if (powerEntityInfo[i].states != null) {
+                    final int statesLength = powerEntityInfo[i].states.length;
+                    for (int j = 0; j < statesLength; j++) {
+                        final StateInfo state = powerEntityInfo[i].states[j];
+                        long siToken = pos.start(PowerEntityInfoProto.STATES);
+                        pos.write(StateInfoProto.STATE_ID, state.stateId);
+                        pos.write(StateInfoProto.STATE_NAME, state.stateName);
+                        pos.end(siToken);
+                    }
+                }
+                pos.end(peiToken);
+            }
+        }
+
         public static void print(PowerEntityInfo[] powerEntityInfo) {
             if (powerEntityInfo == null) return;
 
@@ -77,6 +102,144 @@
     }
 
     static class StateResidencyResultUtils {
+        public static byte[] getProtoBytes(StateResidencyResult[] stateResidencyResult) {
+            ProtoOutputStream pos = new ProtoOutputStream();
+            packProtoMessage(stateResidencyResult, pos);
+            return pos.getBytes();
+        }
+
+        public static void packProtoMessage(StateResidencyResult[] stateResidencyResult,
+                ProtoOutputStream pos) {
+            if (stateResidencyResult == null) return;
+
+            for (int i = 0; i < stateResidencyResult.length; i++) {
+                final int stateLength = stateResidencyResult[i].stateResidencyData.length;
+                long srrToken = pos.start(PowerStatsServiceResidencyProto.STATE_RESIDENCY_RESULT);
+                pos.write(StateResidencyResultProto.POWER_ENTITY_ID,
+                        stateResidencyResult[i].powerEntityId);
+                for (int j = 0; j < stateLength; j++) {
+                    final StateResidency stateResidencyData =
+                            stateResidencyResult[i].stateResidencyData[j];
+                    long srdToken = pos.start(StateResidencyResultProto.STATE_RESIDENCY_DATA);
+                    pos.write(StateResidencyProto.STATE_ID, stateResidencyData.stateId);
+                    pos.write(StateResidencyProto.TOTAL_TIME_IN_STATE_MS,
+                            stateResidencyData.totalTimeInStateMs);
+                    pos.write(StateResidencyProto.TOTAL_STATE_ENTRY_COUNT,
+                            stateResidencyData.totalStateEntryCount);
+                    pos.write(StateResidencyProto.LAST_ENTRY_TIMESTAMP_MS,
+                            stateResidencyData.lastEntryTimestampMs);
+                    pos.end(srdToken);
+                }
+                pos.end(srrToken);
+            }
+        }
+
+        public static StateResidencyResult[] unpackProtoMessage(byte[] data) throws IOException {
+            final ProtoInputStream pis = new ProtoInputStream(new ByteArrayInputStream(data));
+            List<StateResidencyResult> stateResidencyResultList =
+                    new ArrayList<StateResidencyResult>();
+            while (true) {
+                try {
+                    int nextField = pis.nextField();
+                    StateResidencyResult stateResidencyResult = new StateResidencyResult();
+
+                    if (nextField == (int) PowerStatsServiceResidencyProto.STATE_RESIDENCY_RESULT) {
+                        long token =
+                                pis.start(PowerStatsServiceResidencyProto.STATE_RESIDENCY_RESULT);
+                        stateResidencyResultList.add(unpackStateResidencyResultProto(pis));
+                        pis.end(token);
+                    } else if (nextField == ProtoInputStream.NO_MORE_FIELDS) {
+                        return stateResidencyResultList.toArray(
+                            new StateResidencyResult[stateResidencyResultList.size()]);
+                    } else {
+                        Slog.e(TAG, "Unhandled field in PowerStatsServiceResidencyProto: "
+                                + ProtoUtils.currentFieldToString(pis));
+                    }
+                } catch (WireTypeMismatchException wtme) {
+                    Slog.e(TAG, "Wire Type mismatch in PowerStatsServiceResidencyProto: "
+                            + ProtoUtils.currentFieldToString(pis));
+                }
+            }
+        }
+
+        private static StateResidencyResult unpackStateResidencyResultProto(ProtoInputStream pis)
+                throws IOException {
+            StateResidencyResult stateResidencyResult = new StateResidencyResult();
+            List<StateResidency> stateResidencyList = new ArrayList<StateResidency>();
+
+            while (true) {
+                try {
+                    switch (pis.nextField()) {
+                        case (int) StateResidencyResultProto.POWER_ENTITY_ID:
+                            stateResidencyResult.powerEntityId =
+                                pis.readInt(StateResidencyResultProto.POWER_ENTITY_ID);
+                            break;
+
+                        case (int) StateResidencyResultProto.STATE_RESIDENCY_DATA:
+                            long token = pis.start(StateResidencyResultProto.STATE_RESIDENCY_DATA);
+                            stateResidencyList.add(unpackStateResidencyProto(pis));
+                            pis.end(token);
+                            break;
+
+                        case ProtoInputStream.NO_MORE_FIELDS:
+                            stateResidencyResult.stateResidencyData = stateResidencyList.toArray(
+                                new StateResidency[stateResidencyList.size()]);
+                            return stateResidencyResult;
+
+                        default:
+                            Slog.e(TAG, "Unhandled field in StateResidencyResultProto: "
+                                    + ProtoUtils.currentFieldToString(pis));
+                            break;
+                    }
+                } catch (WireTypeMismatchException wtme) {
+                    Slog.e(TAG, "Wire Type mismatch in StateResidencyResultProto: "
+                            + ProtoUtils.currentFieldToString(pis));
+                }
+            }
+        }
+
+        private static StateResidency unpackStateResidencyProto(ProtoInputStream pis)
+                throws IOException {
+            StateResidency stateResidency = new StateResidency();
+
+            while (true) {
+                try {
+                    switch (pis.nextField()) {
+                        case (int) StateResidencyProto.STATE_ID:
+                            stateResidency.stateId = pis.readInt(StateResidencyProto.STATE_ID);
+                            break;
+
+                        case (int) StateResidencyProto.TOTAL_TIME_IN_STATE_MS:
+                            stateResidency.totalTimeInStateMs =
+                                pis.readLong(StateResidencyProto.TOTAL_TIME_IN_STATE_MS);
+                            break;
+
+                        case (int) StateResidencyProto.TOTAL_STATE_ENTRY_COUNT:
+                            stateResidency.totalStateEntryCount =
+                                pis.readLong(StateResidencyProto.TOTAL_STATE_ENTRY_COUNT);
+                            break;
+
+                        case (int) StateResidencyProto.LAST_ENTRY_TIMESTAMP_MS:
+                            stateResidency.lastEntryTimestampMs =
+                                pis.readLong(StateResidencyProto.LAST_ENTRY_TIMESTAMP_MS);
+                            break;
+
+                        case ProtoInputStream.NO_MORE_FIELDS:
+                            return stateResidency;
+
+                        default:
+                            Slog.e(TAG, "Unhandled field in StateResidencyProto: "
+                                    + ProtoUtils.currentFieldToString(pis));
+                            break;
+
+                    }
+                } catch (WireTypeMismatchException wtme) {
+                    Slog.e(TAG, "Wire Type mismatch in StateResidencyProto: "
+                            + ProtoUtils.currentFieldToString(pis));
+                }
+            }
+        }
+
         public static void print(StateResidencyResult[] stateResidencyResult) {
             if (stateResidencyResult == null) return;
 
@@ -98,17 +261,14 @@
 
     static class ChannelInfoUtils {
         public static void packProtoMessage(ChannelInfo[] channelInfo, ProtoOutputStream pos) {
-            long token;
-
             if (channelInfo == null) return;
 
             for (int i = 0; i < channelInfo.length; i++) {
-                token = pos.start(PowerStatsServiceMeterProto.CHANNEL_INFO);
+                long token = pos.start(PowerStatsServiceMeterProto.CHANNEL_INFO);
                 pos.write(ChannelInfoProto.CHANNEL_ID, channelInfo[i].channelId);
                 pos.write(ChannelInfoProto.CHANNEL_NAME, channelInfo[i].channelName);
                 pos.end(token);
             }
-
         }
 
         public static void print(ChannelInfo[] channelInfo) {
@@ -139,12 +299,10 @@
 
         public static void packProtoMessage(EnergyMeasurement[] energyMeasurement,
                 ProtoOutputStream pos) {
-            long token;
-
             if (energyMeasurement == null) return;
 
             for (int i = 0; i < energyMeasurement.length; i++) {
-                token = pos.start(PowerStatsServiceMeterProto.ENERGY_MEASUREMENT);
+                long token = pos.start(PowerStatsServiceMeterProto.ENERGY_MEASUREMENT);
                 pos.write(EnergyMeasurementProto.CHANNEL_ID, energyMeasurement[i].channelId);
                 pos.write(EnergyMeasurementProto.TIMESTAMP_MS, energyMeasurement[i].timestampMs);
                 pos.write(EnergyMeasurementProto.ENERGY_UWS, energyMeasurement[i].energyUWs);
@@ -155,7 +313,6 @@
         public static EnergyMeasurement[] unpackProtoMessage(byte[] data) throws IOException {
             final ProtoInputStream pis = new ProtoInputStream(new ByteArrayInputStream(data));
             List<EnergyMeasurement> energyMeasurementList = new ArrayList<EnergyMeasurement>();
-            long token;
 
             while (true) {
                 try {
@@ -163,8 +320,8 @@
                     EnergyMeasurement energyMeasurement = new EnergyMeasurement();
 
                     if (nextField == (int) PowerStatsServiceMeterProto.ENERGY_MEASUREMENT) {
-                        token = pis.start(PowerStatsServiceMeterProto.ENERGY_MEASUREMENT);
-                        energyMeasurementList.add(unpackProtoMessage(pis));
+                        long token = pis.start(PowerStatsServiceMeterProto.ENERGY_MEASUREMENT);
+                        energyMeasurementList.add(unpackEnergyMeasurementProto(pis));
                         pis.end(token);
                     } else if (nextField == ProtoInputStream.NO_MORE_FIELDS) {
                         return energyMeasurementList.toArray(
@@ -180,7 +337,7 @@
             }
         }
 
-        private static EnergyMeasurement unpackProtoMessage(ProtoInputStream pis)
+        private static EnergyMeasurement unpackEnergyMeasurementProto(ProtoInputStream pis)
                 throws IOException {
             EnergyMeasurement energyMeasurement = new EnergyMeasurement();
 
@@ -230,12 +387,10 @@
 
     static class EnergyConsumerIdUtils {
         public static void packProtoMessage(int[] energyConsumerId, ProtoOutputStream pos) {
-            long token;
-
             if (energyConsumerId == null) return;
 
             for (int i = 0; i < energyConsumerId.length; i++) {
-                token = pos.start(PowerStatsServiceModelProto.ENERGY_CONSUMER_ID);
+                long token = pos.start(PowerStatsServiceModelProto.ENERGY_CONSUMER_ID);
                 pos.write(EnergyConsumerIdProto.ENERGY_CONSUMER_ID, energyConsumerId[i]);
                 pos.end(token);
             }
@@ -267,12 +422,10 @@
 
         public static void packProtoMessage(EnergyConsumerResult[] energyConsumerResult,
                 ProtoOutputStream pos) {
-            long token;
-
             if (energyConsumerResult == null) return;
 
             for (int i = 0; i < energyConsumerResult.length; i++) {
-                token = pos.start(PowerStatsServiceModelProto.ENERGY_CONSUMER_RESULT);
+                long token = pos.start(PowerStatsServiceModelProto.ENERGY_CONSUMER_RESULT);
                 pos.write(EnergyConsumerResultProto.ENERGY_CONSUMER_ID,
                         energyConsumerResult[i].energyConsumerId);
                 pos.write(EnergyConsumerResultProto.TIMESTAMP_MS,
@@ -286,16 +439,14 @@
             final ProtoInputStream pis = new ProtoInputStream(new ByteArrayInputStream(data));
             List<EnergyConsumerResult> energyConsumerResultList =
                     new ArrayList<EnergyConsumerResult>();
-            long token;
-
             while (true) {
                 try {
                     int nextField = pis.nextField();
                     EnergyConsumerResult energyConsumerResult = new EnergyConsumerResult();
 
                     if (nextField == (int) PowerStatsServiceModelProto.ENERGY_CONSUMER_RESULT) {
-                        token = pis.start(PowerStatsServiceModelProto.ENERGY_CONSUMER_RESULT);
-                        energyConsumerResultList.add(unpackProtoMessage(pis));
+                        long token = pis.start(PowerStatsServiceModelProto.ENERGY_CONSUMER_RESULT);
+                        energyConsumerResultList.add(unpackEnergyConsumerResultProto(pis));
                         pis.end(token);
                     } else if (nextField == ProtoInputStream.NO_MORE_FIELDS) {
                         return energyConsumerResultList.toArray(
@@ -311,7 +462,7 @@
             }
         }
 
-        private static EnergyConsumerResult unpackProtoMessage(ProtoInputStream pis)
+        private static EnergyConsumerResult unpackEnergyConsumerResultProto(ProtoInputStream pis)
                 throws IOException {
             EnergyConsumerResult energyConsumerResult = new EnergyConsumerResult();
 
diff --git a/services/core/java/com/android/server/powerstats/TimerTrigger.java b/services/core/java/com/android/server/powerstats/TimerTrigger.java
index 4b59295..7cba00f 100644
--- a/services/core/java/com/android/server/powerstats/TimerTrigger.java
+++ b/services/core/java/com/android/server/powerstats/TimerTrigger.java
@@ -29,7 +29,7 @@
     private static final String TAG = TimerTrigger.class.getSimpleName();
     private static final boolean DEBUG = false;
     // TODO(b/166689029): Make configurable through global settings.
-    private static final long LOG_PERIOD_MS = 60 * 1000;
+    private static final long LOG_PERIOD_MS = 120 * 1000;
 
     private final Handler mHandler;
 
@@ -40,7 +40,7 @@
             // LOG_PERIOD_MS.
             mHandler.postDelayed(mLogData, LOG_PERIOD_MS);
             if (DEBUG) Slog.d(TAG, "Received delayed message.  Log rail data");
-            logPowerStatsData();
+            logPowerStatsData(PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE_TIMER);
         }
     };
 
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index 35c9f9a..3a08ddc 100644
--- a/services/core/java/com/android/server/rollback/RollbackStore.java
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -25,6 +25,8 @@
 import android.content.rollback.PackageRollbackInfo.RestoreInfo;
 import android.content.rollback.RollbackInfo;
 import android.os.UserHandle;
+import android.system.ErrnoException;
+import android.system.Os;
 import android.util.AtomicFile;
 import android.util.Slog;
 import android.util.SparseIntArray;
@@ -237,8 +239,19 @@
         targetDir.mkdirs();
         File targetFile = new File(targetDir, sourceFile.getName());
 
-        // TODO: Copy by hard link instead to save on cpu and storage space?
-        Files.copy(sourceFile.toPath(), targetFile.toPath());
+        try {
+            // Create a hard link to avoid copy
+            // TODO(b/168562373)
+            // Linking between non-encrypted and encrypted is not supported and we have
+            // encrypted /data/rollback and non-encrypted /data/apex/active. For now this works
+            // because we happen to store encrypted files under /data/apex/active which is no
+            // longer the case when compressed apex rolls out. We have to handle this case in
+            // order not to fall back to copy.
+            Os.link(sourceFile.getAbsolutePath(), targetFile.getAbsolutePath());
+        } catch (ErrnoException ignore) {
+            // Fall back to copy if hardlink can't be created
+            Files.copy(sourceFile.toPath(), targetFile.toPath());
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 638232d..d656617 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -138,7 +138,6 @@
 import com.android.internal.os.BatterySipper;
 import com.android.internal.os.BatteryStatsHelper;
 import com.android.internal.os.BinderCallsStats.ExportedCallStat;
-import com.android.internal.os.KernelCpuSpeedReader;
 import com.android.internal.os.KernelCpuThreadReader;
 import com.android.internal.os.KernelCpuThreadReaderDiff;
 import com.android.internal.os.KernelCpuThreadReaderSettingsObserver;
@@ -301,8 +300,6 @@
     @GuardedBy("mDiskIoLock")
     private StoragedUidIoStatsReader mStoragedUidIoStatsReader;
 
-    @GuardedBy("mCpuTimePerFreqLock")
-    private KernelCpuSpeedReader[] mKernelCpuSpeedReaders;
     // Disables throttler on CPU time readers.
     @GuardedBy("mCpuTimePerUidLock")
     private KernelCpuUidUserSysTimeReader mCpuUidUserSysTimeReader;
@@ -353,7 +350,6 @@
     private final Object mDataBytesTransferLock = new Object();
     private final Object mBluetoothBytesTransferLock = new Object();
     private final Object mKernelWakelockLock = new Object();
-    private final Object mCpuTimePerFreqLock = new Object();
     private final Object mCpuTimePerUidLock = new Object();
     private final Object mCpuTimePerUidFreqLock = new Object();
     private final Object mCpuActiveTimeLock = new Object();
@@ -442,10 +438,6 @@
                         synchronized (mKernelWakelockLock) {
                             return pullKernelWakelockLocked(atomTag, data);
                         }
-                    case FrameworkStatsLog.CPU_TIME_PER_FREQ:
-                        synchronized (mCpuTimePerFreqLock) {
-                            return pullCpuTimePerFreqLocked(atomTag, data);
-                        }
                     case FrameworkStatsLog.CPU_TIME_PER_UID:
                         synchronized (mCpuTimePerUidLock) {
                             return pullCpuTimePerUidLocked(atomTag, data);
@@ -722,18 +714,6 @@
         mKernelWakelockReader = new KernelWakelockReader();
         mTmpWakelockStats = new KernelWakelockStats();
 
-        // Initialize state for CPU_TIME_PER_FREQ atom
-        PowerProfile powerProfile = new PowerProfile(mContext);
-        final int numClusters = powerProfile.getNumCpuClusters();
-        mKernelCpuSpeedReaders = new KernelCpuSpeedReader[numClusters];
-        int firstCpuOfCluster = 0;
-        for (int i = 0; i < numClusters; i++) {
-            final int numSpeedSteps = powerProfile.getNumSpeedStepsInCpuCluster(i);
-            mKernelCpuSpeedReaders[i] = new KernelCpuSpeedReader(firstCpuOfCluster,
-                    numSpeedSteps);
-            firstCpuOfCluster += powerProfile.getNumCoresInCpuCluster(i);
-        }
-
         // Used for CPU_TIME_PER_THREAD_FREQ
         mKernelCpuThreadReader =
                 KernelCpuThreadReaderSettingsObserver.getSettingsModifiedReader(mContext);
@@ -793,7 +773,6 @@
         mStatsCallbackImpl = new StatsPullAtomCallbackImpl();
         registerBluetoothBytesTransfer();
         registerKernelWakelock();
-        registerCpuTimePerFreq();
         registerCpuTimePerUid();
         registerCpuCyclesPerUidCluster();
         registerCpuTimePerUidFreq();
@@ -1465,32 +1444,6 @@
         return StatsManager.PULL_SUCCESS;
     }
 
-    private void registerCpuTimePerFreq() {
-        int tagId = FrameworkStatsLog.CPU_TIME_PER_FREQ;
-        PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                .setAdditiveFields(new int[] {3})
-                .build();
-        mStatsManager.setPullAtomCallback(
-                tagId,
-                metadata,
-                DIRECT_EXECUTOR,
-                mStatsCallbackImpl
-        );
-    }
-
-    int pullCpuTimePerFreqLocked(int atomTag, List<StatsEvent> pulledData) {
-        for (int cluster = 0; cluster < mKernelCpuSpeedReaders.length; cluster++) {
-            long[] clusterTimeMs = mKernelCpuSpeedReaders[cluster].readAbsolute();
-            if (clusterTimeMs != null) {
-                for (int speed = clusterTimeMs.length - 1; speed >= 0; --speed) {
-                    pulledData.add(FrameworkStatsLog.buildStatsEvent(
-                            atomTag, cluster, speed, clusterTimeMs[speed]));
-                }
-            }
-        }
-        return StatsManager.PULL_SUCCESS;
-    }
-
     private void registerCpuTimePerUid() {
         int tagId = FrameworkStatsLog.CPU_TIME_PER_UID;
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
@@ -2078,7 +2031,8 @@
                         metrics.pageTablesKb,
                         metrics.kernelStackKb,
                         metrics.totalIonKb,
-                        metrics.unaccountedKb));
+                        metrics.unaccountedKb,
+                        metrics.gpuTotalUsageKb));
         return StatsManager.PULL_SUCCESS;
     }
 
diff --git a/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java b/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java
index 99fc7c1..1e80c4f 100644
--- a/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java
+++ b/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java
@@ -27,6 +27,7 @@
 
     static Metrics getMetrics() {
         int totalIonKb = (int) Debug.getIonHeapsSizeKb();
+        int gpuTotalUsageKb = (int) Debug.getGpuTotalUsageKb();
 
         long[] mInfos = new long[Debug.MEMINFO_COUNT];
         Debug.getMemInfo(mInfos);
@@ -62,6 +63,7 @@
         result.pageTablesKb = (int) mInfos[Debug.MEMINFO_PAGE_TABLES];
         result.kernelStackKb = (int) mInfos[Debug.MEMINFO_KERNEL_STACK];
         result.totalIonKb = totalIonKb;
+        result.gpuTotalUsageKb = gpuTotalUsageKb;
         result.unaccountedKb = (int) (mInfos[Debug.MEMINFO_TOTAL] - accountedKb);
         return result;
     }
@@ -72,6 +74,7 @@
         public int pageTablesKb;
         public int kernelStackKb;
         public int totalIonKb;
+        public int gpuTotalUsageKb;
         public int unaccountedKb;
     }
 }
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
index 865571e..d0c6323 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
@@ -18,6 +18,8 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
 import android.app.time.ITimeZoneDetectorListener;
 import android.app.time.TimeZoneCapabilitiesAndConfig;
 import android.app.time.TimeZoneConfiguration;
@@ -26,12 +28,14 @@
 import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
 import android.content.Context;
 import android.location.LocationManager;
+import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
 import android.os.SystemProperties;
+import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.IndentingPrintWriter;
 import android.util.Slog;
@@ -163,9 +167,13 @@
     @Override
     @NonNull
     public TimeZoneCapabilitiesAndConfig getCapabilitiesAndConfig() {
+        int userId = mCallerIdentityInjector.getCallingUserId();
+        return getCapabilitiesAndConfig(userId);
+    }
+
+    TimeZoneCapabilitiesAndConfig getCapabilitiesAndConfig(@UserIdInt int userId) {
         enforceManageTimeZoneDetectorPermission();
 
-        int userId = mCallerIdentityInjector.getCallingUserId();
         final long token = mCallerIdentityInjector.clearCallingIdentity();
         try {
             ConfigurationInternal configurationInternal =
@@ -178,13 +186,22 @@
 
     @Override
     public boolean updateConfiguration(@NonNull TimeZoneConfiguration configuration) {
+        int callingUserId = mCallerIdentityInjector.getCallingUserId();
+        return updateConfiguration(callingUserId, configuration);
+    }
+
+    boolean updateConfiguration(
+            @UserIdInt int userId, @NonNull TimeZoneConfiguration configuration) {
+        userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+                userId, false, false, "updateConfiguration", null);
+
         enforceManageTimeZoneDetectorPermission();
+
         Objects.requireNonNull(configuration);
 
-        int callingUserId = mCallerIdentityInjector.getCallingUserId();
         final long token = mCallerIdentityInjector.clearCallingIdentity();
         try {
-            return mTimeZoneDetectorStrategy.updateConfiguration(callingUserId, configuration);
+            return mTimeZoneDetectorStrategy.updateConfiguration(userId, configuration);
         } finally {
             mCallerIdentityInjector.restoreCallingIdentity(token);
         }
@@ -318,11 +335,17 @@
         return isGeoLocationTimeZoneDetectionEnabled(mContext);
     }
 
-    boolean isLocationEnabled() {
+    boolean isLocationEnabled(@UserIdInt int userId) {
         enforceManageTimeZoneDetectorPermission();
 
-        return mContext.getSystemService(LocationManager.class)
-                .isLocationEnabledForUser(mContext.getUser());
+        final long token = mCallerIdentityInjector.clearCallingIdentity();
+        try {
+            UserHandle user = UserHandle.of(userId);
+            LocationManager locationManager = mContext.getSystemService(LocationManager.class);
+            return locationManager.isLocationEnabledForUser(user);
+        } finally {
+            mCallerIdentityInjector.restoreCallingIdentity(token);
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java
index b263030..e965f55 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java
@@ -29,6 +29,7 @@
 import android.app.timezonedetector.ManualTimeZoneSuggestion;
 import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
 import android.os.ShellCommand;
+import android.os.UserHandle;
 
 import java.io.PrintWriter;
 import java.util.function.Consumer;
@@ -76,7 +77,8 @@
 
     private int runIsAutoDetectionEnabled() {
         final PrintWriter pw = getOutPrintWriter();
-        boolean enabled = mInterface.getCapabilitiesAndConfig()
+        int userId = UserHandle.USER_CURRENT;
+        boolean enabled = mInterface.getCapabilitiesAndConfig(userId)
                 .getConfiguration()
                 .isAutoDetectionEnabled();
         pw.println(enabled);
@@ -92,14 +94,16 @@
 
     private int runIsLocationEnabled() {
         final PrintWriter pw = getOutPrintWriter();
-        boolean enabled = mInterface.isLocationEnabled();
+        int userId = UserHandle.USER_CURRENT;
+        boolean enabled = mInterface.isLocationEnabled(userId);
         pw.println(enabled);
         return 0;
     }
 
     private int runIsGeoDetectionEnabled() {
         final PrintWriter pw = getOutPrintWriter();
-        boolean enabled = mInterface.getCapabilitiesAndConfig()
+        int userId = UserHandle.USER_CURRENT;
+        boolean enabled = mInterface.getCapabilitiesAndConfig(userId)
                 .getConfiguration()
                 .isGeoDetectionEnabled();
         pw.println(enabled);
@@ -108,18 +112,20 @@
 
     private int runSetAutoDetectionEnabled() {
         boolean enabled = Boolean.parseBoolean(getNextArgRequired());
+        int userId = UserHandle.USER_CURRENT;
         TimeZoneConfiguration configuration = new TimeZoneConfiguration.Builder()
                 .setAutoDetectionEnabled(enabled)
                 .build();
-        return mInterface.updateConfiguration(configuration) ? 0 : 1;
+        return mInterface.updateConfiguration(userId, configuration) ? 0 : 1;
     }
 
     private int runSetGeoDetectionEnabled() {
         boolean enabled = Boolean.parseBoolean(getNextArgRequired());
+        int userId = UserHandle.USER_CURRENT;
         TimeZoneConfiguration configuration = new TimeZoneConfiguration.Builder()
                 .setGeoDetectionEnabled(enabled)
                 .build();
-        return mInterface.updateConfiguration(configuration) ? 0 : 1;
+        return mInterface.updateConfiguration(userId, configuration) ? 0 : 1;
     }
 
     private int runSuggestGeolocationTimeZone() {
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index b084787..03cf021 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -174,6 +174,10 @@
         boolean allDrawn() {
             return mAssociatedTransitionInfo != null && mAssociatedTransitionInfo.allDrawn();
         }
+
+        boolean contains(ActivityRecord r) {
+            return mAssociatedTransitionInfo != null && mAssociatedTransitionInfo.contains(r);
+        }
     }
 
     /** The information created when an activity is confirmed to be launched. */
@@ -793,6 +797,7 @@
 
         stopLaunchTrace(info);
         if (abort) {
+            mSupervisor.stopWaitingForActivityVisible(info.mLastLaunchedActivity);
             launchObserverNotifyActivityLaunchCancelled(info);
         } else {
             if (info.isInterestingToLoggerAndObserver()) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 324e3ac..a9c5474 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -5435,7 +5435,7 @@
         final TransitionInfoSnapshot info = mTaskSupervisor
             .getActivityMetricsLogger().logAppTransitionReportedDrawn(this, restoredFromBundle);
         if (info != null) {
-            mTaskSupervisor.reportActivityLaunchedLocked(false /* timeout */, this,
+            mTaskSupervisor.reportActivityLaunched(false /* timeout */, this,
                     info.windowsFullyDrawnDelayMs, info.getLaunchState());
         }
     }
@@ -5476,9 +5476,8 @@
         // so there is no valid info. But if it is the current top activity (e.g. sleeping), the
         // invalid state is still reported to make sure the waiting result is notified.
         if (validInfo || this == getDisplayArea().topRunningActivity()) {
-            mTaskSupervisor.reportActivityLaunchedLocked(false /* timeout */, this,
+            mTaskSupervisor.reportActivityLaunched(false /* timeout */, this,
                     windowsDrawnDelayMs, launchState);
-            mTaskSupervisor.stopWaitingForActivityVisible(this, windowsDrawnDelayMs, launchState);
         }
         finishLaunchTickingLocked();
         if (task != null) {
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 375c3e1..c6cc83b 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -710,8 +710,12 @@
                 // WaitResult.
                 mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState, res,
                         mLastStartActivityRecord, originalOptions);
-                return getExternalResult(mRequest.waitResult == null ? res
-                        : waitForResult(res, mLastStartActivityRecord));
+                if (mRequest.waitResult != null) {
+                    mRequest.waitResult.result = res;
+                    res = waitResultIfNeeded(mRequest.waitResult, mLastStartActivityRecord,
+                            launchingState);
+                }
+                return getExternalResult(res);
             }
         } finally {
             onExecutionComplete();
@@ -796,48 +800,21 @@
     /**
      * Wait for activity launch completes.
      */
-    private int waitForResult(int res, ActivityRecord r) {
-        mRequest.waitResult.result = res;
-        switch(res) {
-            case START_SUCCESS: {
-                mSupervisor.mWaitingActivityLaunched.add(mRequest.waitResult);
-                do {
-                    try {
-                        mService.mGlobalLock.wait();
-                    } catch (InterruptedException e) {
-                    }
-                } while (mRequest.waitResult.result != START_TASK_TO_FRONT
-                        && !mRequest.waitResult.timeout && mRequest.waitResult.who == null);
-                if (mRequest.waitResult.result == START_TASK_TO_FRONT) {
-                    res = START_TASK_TO_FRONT;
-                }
-                break;
-            }
-            case START_DELIVERED_TO_TOP: {
-                mRequest.waitResult.timeout = false;
-                mRequest.waitResult.who = r.mActivityComponent;
-                mRequest.waitResult.totalTime = 0;
-                break;
-            }
-            case START_TASK_TO_FRONT: {
-                // ActivityRecord may represent a different activity, but it should not be
-                // in the resumed state.
-                if (r.nowVisible && r.isState(RESUMED)) {
-                    mRequest.waitResult.timeout = false;
-                    mRequest.waitResult.who = r.mActivityComponent;
-                    mRequest.waitResult.totalTime = 0;
-                } else {
-                    mSupervisor.waitActivityVisible(r.mActivityComponent, mRequest.waitResult);
-                    // Note: the timeout variable is not currently not ever set.
-                    do {
-                        try {
-                            mService.mGlobalLock.wait();
-                        } catch (InterruptedException e) {
-                        }
-                    } while (!mRequest.waitResult.timeout && mRequest.waitResult.who == null);
-                }
-                break;
-            }
+    private int waitResultIfNeeded(WaitResult waitResult, ActivityRecord r,
+            LaunchingState launchingState) {
+        final int res = waitResult.result;
+        if (res == START_DELIVERED_TO_TOP
+                || (res == START_TASK_TO_FRONT && r.nowVisible && r.isState(RESUMED))) {
+            // The activity should already be visible, so nothing to wait.
+            waitResult.timeout = false;
+            waitResult.who = r.mActivityComponent;
+            waitResult.totalTime = 0;
+            return res;
+        }
+        mSupervisor.waitActivityVisibleOrLaunched(waitResult, r, launchingState);
+        if (res == START_SUCCESS && waitResult.result == START_TASK_TO_FRONT) {
+            // A trampoline activity is launched and it brings another existing activity to front.
+            return START_TASK_TO_FRONT;
         }
         return res;
     }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 08e16c4..9ffedde 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -285,14 +285,6 @@
     public abstract void enforceCallerIsRecentsOrHasPermission(String permission, String func);
 
     /**
-     * Returns true if the app can close system dialogs. Otherwise it either throws a {@link
-     * SecurityException} or returns false with a logcat message depending on whether the app
-     * targets SDK level {@link android.os.Build.VERSION_CODES#S} or not.
-     */
-    public abstract boolean checkCanCloseSystemDialogs(int pid, int uid,
-            @Nullable String packageName);
-
-    /**
      * Called after the voice interaction service has changed.
      */
     public abstract void notifyActiveVoiceInteractionServiceChanged(ComponentName component);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 9b9af06..461bbfb 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -147,7 +147,6 @@
 import android.app.admin.DevicePolicyCache;
 import android.app.assist.AssistContent;
 import android.app.assist.AssistStructure;
-import android.app.compat.CompatChanges;
 import android.app.usage.UsageStatsManagerInternal;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
@@ -2901,86 +2900,6 @@
         }
     }
 
-    /**
-     * Returns true if the app can close system dialogs. Otherwise it either throws a {@link
-     * SecurityException} or returns false with a logcat message depending on whether the app
-     * targets SDK level {@link android.os.Build.VERSION_CODES#S} or not.
-     */
-    private boolean checkCanCloseSystemDialogs(int pid, int uid, @Nullable String packageName) {
-        final WindowProcessController process;
-        synchronized (mGlobalLock) {
-            process = mProcessMap.getProcess(pid);
-        }
-        if (packageName == null && process != null) {
-            // WindowProcessController.mInfo is final, so after the synchronized memory barrier
-            // above, process.mInfo can't change. As for reading mInfo.packageName,
-            // WindowProcessController doesn't own the ApplicationInfo object referenced by mInfo.
-            // ProcessRecord for example also holds a reference to that object, so protecting access
-            // to packageName with the WM lock would not be enough as we'd also need to synchronize
-            // on the AM lock if we are worried about races, but we can't synchronize on AM lock
-            // here. Hence, since this is only used for logging, we don't synchronize here.
-            packageName = process.mInfo.packageName;
-        }
-        String caller = "(pid=" + pid + ", uid=" + uid + ")";
-        if (packageName != null) {
-            caller = packageName + " " + caller;
-        }
-        if (!canCloseSystemDialogs(pid, uid, process)) {
-            // The app can't close system dialogs, throw only if it targets S+
-            if (CompatChanges.isChangeEnabled(
-                    ActivityManager.LOCK_DOWN_CLOSE_SYSTEM_DIALOGS, uid)) {
-                throw new SecurityException(
-                        "Permission Denial: " + Intent.ACTION_CLOSE_SYSTEM_DIALOGS
-                                + " broadcast from " + caller + " requires "
-                                + Manifest.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS + ".");
-            } else if (CompatChanges.isChangeEnabled(
-                    ActivityManager.DROP_CLOSE_SYSTEM_DIALOGS, uid)) {
-                Slog.e(TAG,
-                        "Permission Denial: " + Intent.ACTION_CLOSE_SYSTEM_DIALOGS
-                                + " broadcast from " + caller + " requires "
-                                + Manifest.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS
-                                + ", dropping broadcast.");
-                return false;
-            } else {
-                Slog.w(TAG, Intent.ACTION_CLOSE_SYSTEM_DIALOGS
-                        + " broadcast from " + caller + " will require "
-                        + Manifest.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS
-                        + " in future builds.");
-                return true;
-            }
-        }
-        return true;
-    }
-
-    private boolean canCloseSystemDialogs(int pid, int uid,
-            @Nullable WindowProcessController process) {
-        if (checkPermission(Manifest.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS, pid, uid)
-                == PERMISSION_GRANTED) {
-            return true;
-        }
-        if (process != null) {
-            // Check if the instrumentation of the process has the permission. This covers the
-            // usual test started from the shell (which has the permission) case. This is needed
-            // for apps targeting SDK level < S but we are also allowing for targetSdk S+ as a
-            // convenience to avoid breaking a bunch of existing tests and asking them to adopt
-            // shell permissions to do this.
-            // Note that these getters all read from volatile fields in WindowProcessController, so
-            // no need to lock.
-            int sourceUid = process.getInstrumentationSourceUid();
-            if (process.isInstrumenting() && sourceUid != -1 && checkPermission(
-                    Manifest.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS, -1, sourceUid)
-                    == PERMISSION_GRANTED) {
-                return true;
-            }
-            // This is the notification trampoline use-case for example, where apps use Intent.ACSD
-            // to close the shade prior to starting an activity.
-            if (process.canCloseSystemDialogsByToken()) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     static void enforceTaskPermission(String func) {
         if (checkCallingPermission(MANAGE_ACTIVITY_TASKS) == PackageManager.PERMISSION_GRANTED) {
             return;
@@ -5231,12 +5150,6 @@
         }
 
         @Override
-        public boolean checkCanCloseSystemDialogs(int pid, int uid, @Nullable String packageName) {
-            return ActivityTaskManagerService.this.checkCanCloseSystemDialogs(pid, uid,
-                    packageName);
-        }
-
-        @Override
         public void notifyActiveVoiceInteractionServiceChanged(ComponentName component) {
             synchronized (mGlobalLock) {
                 mActiveVoiceInteractionServiceComponent = component;
@@ -5736,12 +5649,9 @@
         @Override
         public void closeSystemDialogs(String reason) {
             enforceNotIsolatedCaller("closeSystemDialogs");
+
             final int pid = Binder.getCallingPid();
             final int uid = Binder.getCallingUid();
-            if (!checkCanCloseSystemDialogs(pid, uid, null)) {
-                return;
-            }
-
             final long origId = Binder.clearCallingIdentity();
             try {
                 synchronized (mGlobalLock) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 73a6efd..599bf37 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -266,11 +266,8 @@
      */
     private final SparseIntArray mCurTaskIdForUser = new SparseIntArray(20);
 
-    /** List of processes waiting to find out when a specific activity becomes visible. */
-    private final ArrayList<WaitInfo> mWaitingForActivityVisible = new ArrayList<>();
-
-    /** List of processes waiting to find out about the next launched activity. */
-    final ArrayList<WaitResult> mWaitingActivityLaunched = new ArrayList<>();
+    /** List of requests waiting for the target activity to be launched or visible. */
+    private final ArrayList<WaitInfo> mWaitingActivityLaunched = new ArrayList<>();
 
     /** List of activities that are ready to be stopped, but waiting for the next activity to
      * settle down before doing so. */
@@ -552,9 +549,21 @@
         return candidateTaskId;
     }
 
-    void waitActivityVisible(ComponentName name, WaitResult result) {
-        final WaitInfo waitInfo = new WaitInfo(name, result);
-        mWaitingForActivityVisible.add(waitInfo);
+    void waitActivityVisibleOrLaunched(WaitResult w, ActivityRecord r,
+            LaunchingState launchingState) {
+        if (w.result != ActivityManager.START_TASK_TO_FRONT
+                && w.result != ActivityManager.START_SUCCESS) {
+            // Not a result code that can make activity visible or launched.
+            return;
+        }
+        final WaitInfo waitInfo = new WaitInfo(w, r.mActivityComponent, launchingState);
+        mWaitingActivityLaunched.add(waitInfo);
+        do {
+            try {
+                mService.mGlobalLock.wait();
+            } catch (InterruptedException ignored) {
+            }
+        } while (mWaitingActivityLaunched.contains(waitInfo));
     }
 
     void cleanupActivity(ActivityRecord r) {
@@ -568,23 +577,25 @@
 
     /** There is no valid launch time, just stop waiting. */
     void stopWaitingForActivityVisible(ActivityRecord r) {
-        stopWaitingForActivityVisible(r, WaitResult.INVALID_DELAY, WaitResult.LAUNCH_STATE_UNKNOWN);
+        reportActivityLaunched(false /* timeout */, r, WaitResult.INVALID_DELAY,
+                WaitResult.LAUNCH_STATE_UNKNOWN);
     }
 
-    void stopWaitingForActivityVisible(ActivityRecord r, long totalTime,
+    void reportActivityLaunched(boolean timeout, ActivityRecord r, long totalTime,
             @WaitResult.LaunchState int launchState) {
         boolean changed = false;
-        for (int i = mWaitingForActivityVisible.size() - 1; i >= 0; --i) {
-            final WaitInfo w = mWaitingForActivityVisible.get(i);
-            if (w.matches(r.mActivityComponent)) {
-                final WaitResult result = w.getResult();
-                changed = true;
-                result.timeout = false;
-                result.who = w.getComponent();
-                result.totalTime = totalTime;
-                result.launchState = launchState;
-                mWaitingForActivityVisible.remove(w);
+        for (int i = mWaitingActivityLaunched.size() - 1; i >= 0; i--) {
+            final WaitInfo info = mWaitingActivityLaunched.get(i);
+            if (!info.matches(r)) {
+                continue;
             }
+            final WaitResult w = info.mResult;
+            w.timeout = timeout;
+            w.who = r.mActivityComponent;
+            w.totalTime = totalTime;
+            w.launchState = launchState;
+            mWaitingActivityLaunched.remove(i);
+            changed = true;
         }
         if (changed) {
             mService.mGlobalLock.notifyAll();
@@ -603,38 +614,18 @@
         boolean changed = false;
 
         for (int i = mWaitingActivityLaunched.size() - 1; i >= 0; i--) {
-            WaitResult w = mWaitingActivityLaunched.remove(i);
-            if (w.who == null) {
-                changed = true;
-                w.result = result;
-
+            final WaitInfo info = mWaitingActivityLaunched.get(i);
+            if (!info.matches(r)) {
+                continue;
+            }
+            final WaitResult w = info.mResult;
+            w.result = result;
+            if (result == START_DELIVERED_TO_TOP) {
                 // Unlike START_TASK_TO_FRONT, When an intent is delivered to top, there
                 // will be no followup launch signals. Assign the result and launched component.
-                if (result == START_DELIVERED_TO_TOP) {
-                    w.who = r.mActivityComponent;
-                }
-            }
-        }
-
-        if (changed) {
-            mService.mGlobalLock.notifyAll();
-        }
-    }
-
-    void reportActivityLaunchedLocked(boolean timeout, ActivityRecord r, long totalTime,
-            @WaitResult.LaunchState int launchState) {
-        boolean changed = false;
-        for (int i = mWaitingActivityLaunched.size() - 1; i >= 0; i--) {
-            WaitResult w = mWaitingActivityLaunched.remove(i);
-            if (w.who == null) {
+                w.who = r.mActivityComponent;
+                mWaitingActivityLaunched.remove(i);
                 changed = true;
-                w.timeout = timeout;
-                if (r != null) {
-                    w.who = new ComponentName(r.info.packageName, r.info.name);
-                }
-                w.totalTime = totalTime;
-                w.launchState = launchState;
-                // Do not modify w.result.
             }
         }
         if (changed) {
@@ -1295,8 +1286,7 @@
             mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
             r.finishLaunchTickingLocked();
             if (fromTimeout) {
-                reportActivityLaunchedLocked(fromTimeout, r, INVALID_DELAY,
-                        -1 /* launchState */);
+                reportActivityLaunched(fromTimeout, r, INVALID_DELAY, -1 /* launchState */);
             }
 
             // This is a hack to semi-deal with a race condition
@@ -1940,14 +1930,14 @@
         pw.println("mCurTaskIdForUser=" + mCurTaskIdForUser);
         pw.println(prefix + "mUserRootTaskInFront=" + mRootWindowContainer.mUserRootTaskInFront);
         pw.println(prefix + "mVisibilityTransactionDepth=" + mVisibilityTransactionDepth);
-        if (!mWaitingForActivityVisible.isEmpty()) {
-            pw.println(prefix + "mWaitingForActivityVisible=");
-            for (int i = 0; i < mWaitingForActivityVisible.size(); ++i) {
-                pw.print(prefix + prefix); mWaitingForActivityVisible.get(i).dump(pw, prefix);
-            }
-        }
         pw.print(prefix); pw.print("isHomeRecentsComponent=");
         pw.println(mRecentTasks.isRecentsComponentHomeActivity(mRootWindowContainer.mCurrentUser));
+        if (!mWaitingActivityLaunched.isEmpty()) {
+            pw.println(prefix + "mWaitingActivityLaunched=");
+            for (int i = mWaitingActivityLaunched.size() - 1; i >= 0; i--) {
+                mWaitingActivityLaunched.get(i).dump(pw, prefix + "  ");
+            }
+        }
         pw.println();
     }
 
@@ -2604,32 +2594,30 @@
     /**
      * Internal container to store a match qualifier alongside a WaitResult.
      */
-    static class WaitInfo {
-        private final ComponentName mTargetComponent;
-        private final WaitResult mResult;
+    private static class WaitInfo {
+        final WaitResult mResult;
+        final ComponentName mTargetComponent;
+        /**
+         * The target component may not be the final drawn activity. The launching state is managed
+         * by {@link ActivityMetricsLogger} that can track consecutive launching sequence.
+         */
+        final LaunchingState mLaunchingState;
 
-        WaitInfo(ComponentName targetComponent, WaitResult result) {
-            this.mTargetComponent = targetComponent;
-            this.mResult = result;
+        WaitInfo(WaitResult result, ComponentName component, LaunchingState launchingState) {
+            mResult = result;
+            mTargetComponent = component;
+            mLaunchingState = launchingState;
         }
 
-        public boolean matches(ComponentName targetComponent) {
-            return mTargetComponent == null || mTargetComponent.equals(targetComponent);
+        boolean matches(ActivityRecord r) {
+            return mTargetComponent.equals(r.mActivityComponent) || mLaunchingState.contains(r);
         }
 
-        public WaitResult getResult() {
-            return mResult;
-        }
-
-        public ComponentName getComponent() {
-            return mTargetComponent;
-        }
-
-        public void dump(PrintWriter pw, String prefix) {
+        void dump(PrintWriter pw, String prefix) {
             pw.println(prefix + "WaitInfo:");
             pw.println(prefix + "  mTargetComponent=" + mTargetComponent);
             pw.println(prefix + "  mResult=");
-            mResult.dump(pw, prefix);
+            mResult.dump(pw, prefix + "    ");
         }
     }
 }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 1c41978..a88e453 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -5104,7 +5104,9 @@
     }
 
     void onPictureInPictureParamsChanged() {
-        dispatchTaskInfoChangedIfNeeded(true /* force */);
+        if (inPinnedWindowingMode()) {
+            dispatchTaskInfoChangedIfNeeded(true /* force */);
+        }
     }
 
     /**
@@ -5436,14 +5438,6 @@
         r.completeResumeLocked();
     }
 
-    private void clearLaunchTime(ActivityRecord r) {
-        // Make sure that there is no activity waiting for this to launch.
-        if (!mTaskSupervisor.mWaitingActivityLaunched.isEmpty()) {
-            mTaskSupervisor.removeIdleTimeoutForActivity(r);
-            mTaskSupervisor.scheduleIdleTimeout(r);
-        }
-    }
-
     void awakeFromSleepingLocked() {
         if (!isLeafTask()) {
             forAllLeafTasks((task) -> task.awakeFromSleepingLocked(),
@@ -5586,7 +5580,6 @@
         mLastNoHistoryActivity = prev.isNoHistory() ? prev : null;
         prev.setState(PAUSING, "startPausingLocked");
         prev.getTask().touchActiveTime();
-        clearLaunchTime(prev);
 
         mAtmService.updateCpuStats();
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 0b60deb..4eeae6c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2332,9 +2332,15 @@
                 }
             }
 
-            // Create surfaceControl before surface placement otherwise layout will be skipped
-            // (because WS.isGoneForLayout() is true when there is no surface.
+            // We may be deferring layout passes at the moment, but since the client is interested
+            // in the new out values right now we need to force a layout.
+            mWindowPlacerLocked.performSurfacePlacement(true /* force */);
+
             if (shouldRelayout) {
+                Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: viewVisibility_1");
+
+                result = win.relayoutVisibleWindow(result, attrChanges);
+
                 try {
                     result = createSurfaceControl(outSurfaceControl, result, win, winAnimator);
                 } catch (Exception e) {
@@ -2346,17 +2352,6 @@
                     Binder.restoreCallingIdentity(origId);
                     return 0;
                 }
-            }
-
-            // We may be deferring layout passes at the moment, but since the client is interested
-            // in the new out values right now we need to force a layout.
-            mWindowPlacerLocked.performSurfacePlacement(true /* force */);
-
-            if (shouldRelayout) {
-                Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: viewVisibility_1");
-
-                result = win.relayoutVisibleWindow(result, attrChanges);
-
                 if ((result & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
                     focusMayChange = true;
                 }
@@ -3243,11 +3238,6 @@
 
     @Override
     public void closeSystemDialogs(String reason) {
-        int callingPid = Binder.getCallingPid();
-        int callingUid = Binder.getCallingUid();
-        if (!mAtmInternal.checkCanCloseSystemDialogs(callingPid, callingUid, null)) {
-            return;
-        }
         synchronized (mGlobalLock) {
             mRoot.closeSystemDialogs(reason);
         }
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 663d91e..8aa154b 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -23,7 +23,6 @@
 import static android.view.Display.INVALID_DISPLAY;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
-import static com.android.internal.util.Preconditions.checkArgument;
 import static com.android.server.am.ActivityManagerService.MY_PID;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ACTIVITY_STARTS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RELEASE;
@@ -162,8 +161,6 @@
     private volatile boolean mDebugging;
     // Active instrumentation running in process?
     private volatile boolean mInstrumenting;
-    // If there is active instrumentation, this is the source
-    private volatile int mInstrumentationSourceUid = -1;
     // Active instrumentation with background activity starts privilege running in process?
     private volatile boolean mInstrumentingWithBackgroundActivityStartPrivileges;
     // This process it perceptible by the user.
@@ -626,16 +623,9 @@
         mBoundClientUids = boundClientUids;
     }
 
-    /**
-     * Set instrumentation-related info.
-     *
-     * If {@code instrumenting} is {@code false}, {@code sourceUid} has to be -1.
-     */
-    public void setInstrumenting(boolean instrumenting, int sourceUid,
+    public void setInstrumenting(boolean instrumenting,
             boolean hasBackgroundActivityStartPrivileges) {
-        checkArgument(instrumenting || sourceUid == -1);
         mInstrumenting = instrumenting;
-        mInstrumentationSourceUid = sourceUid;
         mInstrumentingWithBackgroundActivityStartPrivileges = hasBackgroundActivityStartPrivileges;
     }
 
@@ -643,11 +633,6 @@
         return mInstrumenting;
     }
 
-    /** Returns the uid of the active instrumentation source if there is one, otherwise -1. */
-    int getInstrumentationSourceUid() {
-        return mInstrumentationSourceUid;
-    }
-
     public void setPerceptible(boolean perceptible) {
         mPerceptible = perceptible;
     }
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 996462f..13078b6 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -171,7 +171,6 @@
 
     static_libs: [
         "android.hardware.broadcastradio@common-utils-1x-lib",
-        "libservice-connectivity-static",
     ],
 
     product_variables: {
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 85ef394..1893321 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -41,8 +41,6 @@
 int register_android_server_vibrator_VibratorController(JavaVM* vm, JNIEnv* env);
 int register_android_server_VibratorManagerService(JNIEnv* env);
 int register_android_server_location_GnssLocationProvider(JNIEnv* env);
-int register_android_server_connectivity_Vpn(JNIEnv* env);
-int register_android_server_TestNetworkService(JNIEnv* env);
 int register_android_server_devicepolicy_CryptoTestHelper(JNIEnv*);
 int register_android_server_tv_TvUinputBridge(JNIEnv* env);
 int register_android_server_tv_TvInputHal(JNIEnv* env);
@@ -96,8 +94,6 @@
     register_android_server_VibratorManagerService(env);
     register_android_server_SystemServer(env);
     register_android_server_location_GnssLocationProvider(env);
-    register_android_server_connectivity_Vpn(env);
-    register_android_server_TestNetworkService(env);
     register_android_server_devicepolicy_CryptoTestHelper(env);
     register_android_server_ConsumerIrService(env);
     register_android_server_BatteryStatsService(env);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index a281180..48f8b15 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -134,6 +134,8 @@
     private static final String TAG_ALWAYS_ON_VPN_LOCKDOWN = "vpn-lockdown";
     private static final String TAG_COMMON_CRITERIA_MODE = "common-criteria-mode";
     private static final String TAG_PASSWORD_COMPLEXITY = "password-complexity";
+    private static final String TAG_ORGANIZATION_ID = "organization-id";
+    private static final String TAG_ENROLLMENT_SPECIFIC_ID = "enrollment-specific-id";
     private static final String ATTR_VALUE = "value";
     private static final String ATTR_LAST_NETWORK_LOGGING_NOTIFICATION = "last-notification";
     private static final String ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS = "num-notifications";
@@ -273,6 +275,8 @@
     public String mAlwaysOnVpnPackage;
     public boolean mAlwaysOnVpnLockdown;
     boolean mCommonCriteriaMode;
+    public String mOrganizationId;
+    public String mEnrollmentSpecificId;
 
     ActiveAdmin(DeviceAdminInfo info, boolean isParent) {
         this.info = info;
@@ -533,6 +537,12 @@
         if (mPasswordComplexity != PASSWORD_COMPLEXITY_NONE) {
             writeAttributeValueToXml(out, TAG_PASSWORD_COMPLEXITY, mPasswordComplexity);
         }
+        if (!TextUtils.isEmpty(mOrganizationId)) {
+            writeTextToXml(out, TAG_ORGANIZATION_ID, mOrganizationId);
+        }
+        if (!TextUtils.isEmpty(mEnrollmentSpecificId)) {
+            writeTextToXml(out, TAG_ENROLLMENT_SPECIFIC_ID, mEnrollmentSpecificId);
+        }
     }
 
     void writeTextToXml(TypedXmlSerializer out, String tag, String text) throws IOException {
@@ -766,6 +776,22 @@
                 mCommonCriteriaMode = parser.getAttributeBoolean(null, ATTR_VALUE, false);
             } else if (TAG_PASSWORD_COMPLEXITY.equals(tag)) {
                 mPasswordComplexity = parser.getAttributeInt(null, ATTR_VALUE);
+            } else if (TAG_ORGANIZATION_ID.equals(tag)) {
+                type = parser.next();
+                if (type == TypedXmlPullParser.TEXT) {
+                    mOrganizationId = parser.getText();
+                } else {
+                    Log.w(DevicePolicyManagerService.LOG_TAG,
+                            "Missing Organization ID.");
+                }
+            } else if (TAG_ENROLLMENT_SPECIFIC_ID.equals(tag)) {
+                type = parser.next();
+                if (type == TypedXmlPullParser.TEXT) {
+                    mEnrollmentSpecificId = parser.getText();
+                } else {
+                    Log.w(DevicePolicyManagerService.LOG_TAG,
+                            "Missing Enrollment-specific ID.");
+                }
             } else {
                 Slog.w(DevicePolicyManagerService.LOG_TAG, "Unknown admin tag: " + tag);
                 XmlUtils.skipCurrentTag(parser);
@@ -1107,5 +1133,15 @@
 
         pw.print("mPasswordComplexity=");
         pw.println(mPasswordComplexity);
+
+        if (!TextUtils.isEmpty(mOrganizationId)) {
+            pw.print("mOrganizationId=");
+            pw.println(mOrganizationId);
+        }
+
+        if (!TextUtils.isEmpty(mEnrollmentSpecificId)) {
+            pw.print("mEnrollmentSpecificId=");
+            pw.println(mEnrollmentSpecificId);
+        }
     }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 6f1d451e..22e9725 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -15,6 +15,7 @@
  */
 package com.android.server.devicepolicy;
 
+import android.annotation.NonNull;
 import android.app.admin.DevicePolicySafetyChecker;
 import android.app.admin.IDevicePolicyManager;
 import android.content.ComponentName;
@@ -101,4 +102,11 @@
     public boolean canProfileOwnerResetPasswordWhenLocked(int userId) {
         return false;
     }
+
+    public String getEnrollmentSpecificId() {
+        return "";
+    }
+
+    public void setOrganizationIdForUser(
+            @NonNull String callerPackage, @NonNull String enterpriseId, int userId) {}
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index fdbd85a..4654fca 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -819,6 +819,7 @@
             } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)
                     && !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
                 handlePackagesChanged(intent.getData().getSchemeSpecificPart(), userHandle);
+                removeCredentialManagementApp(intent.getData().getSchemeSpecificPart());
             } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)) {
                 clearWipeProfileNotification();
             } else if (Intent.ACTION_DATE_CHANGED.equals(action)
@@ -949,6 +950,20 @@
         }
     }
 
+    private void removeCredentialManagementApp(String packageName) {
+        mBackgroundHandler.post(() -> {
+            try (KeyChainConnection connection = mInjector.keyChainBind()) {
+                IKeyChainService service = connection.getService();
+                if (service.hasCredentialManagementApp()
+                        && packageName.equals(service.getCredentialManagementAppPackageName())) {
+                    service.removeCredentialManagementApp();
+                }
+            } catch (RemoteException | InterruptedException | IllegalStateException e) {
+                Log.e(LOG_TAG, "Unable to remove the credential management app");
+            }
+        });
+    }
+
     private boolean isRemovedPackage(String changedPackage, String targetPackage, int userHandle) {
         try {
             return targetPackage != null
@@ -1419,6 +1434,10 @@
             return SecurityLog.isLoggingEnabled();
         }
 
+        KeyChainConnection keyChainBind() throws InterruptedException {
+            return KeyChain.bind(mContext);
+        }
+
         KeyChainConnection keyChainBindAsUser(UserHandle user) throws InterruptedException {
             return KeyChain.bindAsUser(mContext, user);
         }
@@ -8421,7 +8440,10 @@
             return null;
         }
         Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity()));
+        return getProfileOwnerNameUnchecked(userHandle);
+    }
 
+    private String getProfileOwnerNameUnchecked(int userHandle) {
         ComponentName profileOwner = getProfileOwnerAsUser(userHandle);
         if (profileOwner == null) {
             return null;
@@ -9731,7 +9753,8 @@
 
         // Set admin.
         setActiveAdmin(profileOwner, /* refreshing= */ true, userId);
-        final String ownerName = getProfileOwnerName(Process.myUserHandle().getIdentifier());
+        final String ownerName = getProfileOwnerNameUnchecked(
+                Process.myUserHandle().getIdentifier());
         setProfileOwner(profileOwner, ownerName, userId);
 
         synchronized (getLockObject()) {
@@ -15577,4 +15600,69 @@
             return true;
         }
     }
+
+    @Override
+    public String getEnrollmentSpecificId() {
+        if (!mHasFeature) {
+            return "";
+        }
+
+        final CallerIdentity caller = getCallerIdentity();
+        Preconditions.checkCallAuthorization(
+                isDeviceOwner(caller) || isProfileOwner(caller));
+
+        synchronized (getLockObject()) {
+            final ActiveAdmin requiredAdmin = getDeviceOrProfileOwnerAdminLocked(
+                    caller.getUserId());
+            final String esid = requiredAdmin.mEnrollmentSpecificId;
+            return esid != null ? esid : "";
+        }
+    }
+
+    @Override
+    public void setOrganizationIdForUser(
+            @NonNull String callerPackage, @NonNull String organizationId, int userId) {
+        if (!mHasFeature) {
+            return;
+        }
+        Objects.requireNonNull(callerPackage);
+
+        final CallerIdentity caller = getCallerIdentity(callerPackage);
+        // Only the DPC can set this ID.
+        Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller),
+                "Only a Device Owner or Profile Owner may set the Enterprise ID.");
+        // Empty enterprise ID must not be provided in calls to this method.
+        Preconditions.checkArgument(!TextUtils.isEmpty(organizationId),
+                "Enterprise ID may not be empty.");
+
+        Log.i(LOG_TAG,
+                String.format("Setting Enterprise ID to %s for user %d", organizationId, userId));
+
+        synchronized (getLockObject()) {
+            ActiveAdmin owner = getDeviceOrProfileOwnerAdminLocked(userId);
+            // As the caller is the system, it must specify the component name of the profile owner
+            // as a safety check.
+            Preconditions.checkCallAuthorization(
+                    owner != null && owner.getUserHandle().getIdentifier() == userId,
+                    String.format("The Profile Owner or Device Owner may only set the Enterprise ID"
+                            + " on its own user, called on user %d but owner user is %d", userId,
+                            owner.getUserHandle().getIdentifier()));
+            Preconditions.checkState(
+                    TextUtils.isEmpty(owner.mOrganizationId) || owner.mOrganizationId.equals(
+                            organizationId),
+                    "The organization ID has been previously set to a different value and cannot "
+                            + "be changed");
+            final String dpcPackage = owner.info.getPackageName();
+            mInjector.binderWithCleanCallingIdentity(() -> {
+                EnterpriseSpecificIdCalculator esidCalculator =
+                        new EnterpriseSpecificIdCalculator(mContext);
+
+                final String esid = esidCalculator.calculateEnterpriseId(dpcPackage,
+                        organizationId);
+                owner.mOrganizationId = organizationId;
+                owner.mEnrollmentSpecificId = esid;
+                saveSettingsLocked(userId);
+            });
+        }
+    }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java b/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java
new file mode 100644
index 0000000..df7f308
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java
@@ -0,0 +1,145 @@
+/*
+ * 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.devicepolicy;
+
+import android.content.Context;
+import android.content.pm.VerifierDeviceIdentity;
+import android.net.wifi.WifiManager;
+import android.os.Build;
+import android.security.identity.Util;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+
+import java.nio.ByteBuffer;
+
+class EnterpriseSpecificIdCalculator {
+    private static final int PADDED_HW_ID_LENGTH = 16;
+    private static final int PADDED_PROFILE_OWNER_LENGTH = 64;
+    private static final int PADDED_ENTERPRISE_ID_LENGTH = 64;
+    private static final int ESID_LENGTH = 16;
+
+    private final String mImei;
+    private final String mMeid;
+    private final String mSerialNumber;
+    private final String mMacAddress;
+
+    @VisibleForTesting
+    EnterpriseSpecificIdCalculator(String imei, String meid, String serialNumber,
+            String macAddress) {
+        mImei = imei;
+        mMeid = meid;
+        mSerialNumber = serialNumber;
+        mMacAddress = macAddress;
+    }
+
+    EnterpriseSpecificIdCalculator(Context context) {
+        TelephonyManager telephonyService = context.getSystemService(TelephonyManager.class);
+        Preconditions.checkState(telephonyService != null, "Unable to access telephony service");
+        mImei = telephonyService.getImei(0);
+        mMeid = telephonyService.getMeid(0);
+        mSerialNumber = Build.getSerial();
+        WifiManager wifiManager = context.getSystemService(WifiManager.class);
+        Preconditions.checkState(wifiManager != null, "Unable to access WiFi service");
+        final String[] macAddresses = wifiManager.getFactoryMacAddresses();
+        if (macAddresses == null || macAddresses.length == 0) {
+            mMacAddress = "";
+        } else {
+            mMacAddress = macAddresses[0];
+        }
+    }
+
+    private static String getPaddedTruncatedString(String input, int maxLength) {
+        final String paddedValue = String.format("%" + maxLength + "s", input);
+        return paddedValue.substring(0, maxLength);
+    }
+
+    private static String getPaddedHardwareIdentifier(String hardwareIdentifier) {
+        if (hardwareIdentifier == null) {
+            hardwareIdentifier = "";
+        }
+        return getPaddedTruncatedString(hardwareIdentifier, PADDED_HW_ID_LENGTH);
+    }
+
+    String getPaddedImei() {
+        return getPaddedHardwareIdentifier(mImei);
+    }
+
+    String getPaddedMeid() {
+        return getPaddedHardwareIdentifier(mMeid);
+    }
+
+    String getPaddedSerialNumber() {
+        return getPaddedHardwareIdentifier(mSerialNumber);
+    }
+
+    String getPaddedProfileOwnerName(String profileOwnerPackage) {
+        return getPaddedTruncatedString(profileOwnerPackage, PADDED_PROFILE_OWNER_LENGTH);
+    }
+
+    String getPaddedEnterpriseId(String enterpriseId) {
+        return getPaddedTruncatedString(enterpriseId, PADDED_ENTERPRISE_ID_LENGTH);
+    }
+
+    /**
+     * Calculates the ESID.
+     * @param profileOwnerPackage Package of the Device Policy Client that manages the device/
+     *                            profile. May not be null.
+     * @param enterpriseIdString The identifier for the enterprise in which the device/profile is
+     *                           being enrolled. This parameter may not be empty, but may be null.
+     *                           If called with {@code null}, will calculate an ESID with empty
+     *                           Enterprise ID.
+     */
+    public String calculateEnterpriseId(String profileOwnerPackage, String enterpriseIdString) {
+        Preconditions.checkArgument(!TextUtils.isEmpty(profileOwnerPackage),
+                "owner package must be specified.");
+
+        Preconditions.checkArgument(enterpriseIdString == null || !enterpriseIdString.isEmpty(),
+                "enterprise ID must either be null or non-empty.");
+
+        if (enterpriseIdString == null) {
+            enterpriseIdString = "";
+        }
+
+        final byte[] serialNumber = getPaddedSerialNumber().getBytes();
+        final byte[] imei = getPaddedImei().getBytes();
+        final byte[] meid = getPaddedMeid().getBytes();
+        final byte[] macAddress = mMacAddress.getBytes();
+        final int totalIdentifiersLength = serialNumber.length + imei.length + meid.length
+                + macAddress.length;
+        final ByteBuffer fixedIdentifiers = ByteBuffer.allocate(totalIdentifiersLength);
+        fixedIdentifiers.put(serialNumber);
+        fixedIdentifiers.put(imei);
+        fixedIdentifiers.put(meid);
+        fixedIdentifiers.put(macAddress);
+
+        final byte[] dpcPackage = getPaddedProfileOwnerName(profileOwnerPackage).getBytes();
+        final byte[] enterpriseId = getPaddedEnterpriseId(enterpriseIdString).getBytes();
+        final ByteBuffer info = ByteBuffer.allocate(dpcPackage.length + enterpriseId.length);
+        info.put(dpcPackage);
+        info.put(enterpriseId);
+        final byte[] esidBytes = Util.computeHkdf("HMACSHA256", fixedIdentifiers.array(), null,
+                info.array(), ESID_LENGTH);
+        ByteBuffer esidByteBuffer = ByteBuffer.wrap(esidBytes);
+
+        VerifierDeviceIdentity firstId = new VerifierDeviceIdentity(esidByteBuffer.getLong());
+        VerifierDeviceIdentity secondId = new VerifierDeviceIdentity(esidByteBuffer.getLong());
+        return firstId.toString() + secondId.toString();
+    }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 4d15ced..d9350f3 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -237,6 +237,8 @@
             "com.android.server.companion.CompanionDeviceManagerService";
     private static final String STATS_COMPANION_APEX_PATH =
             "/apex/com.android.os.statsd/javalib/service-statsd.jar";
+    private static final String CONNECTIVITY_SERVICE_APEX_PATH =
+            "/apex/com.android.tethering/javalib/service-connectivity.jar";
     private static final String STATS_COMPANION_LIFECYCLE_CLASS =
             "com.android.server.stats.StatsCompanion$Lifecycle";
     private static final String STATS_PULL_ATOM_SERVICE_CLASS =
@@ -1356,7 +1358,8 @@
             }
 
             t.traceBegin("IpConnectivityMetrics");
-            mSystemServiceManager.startService(IP_CONNECTIVITY_METRICS_CLASS);
+            mSystemServiceManager.startServiceFromJar(IP_CONNECTIVITY_METRICS_CLASS,
+                    CONNECTIVITY_SERVICE_APEX_PATH);
             t.traceEnd();
 
             t.traceBegin("NetworkWatchlistService");
@@ -1721,8 +1724,8 @@
             // This has to be called after NetworkManagementService, NetworkStatsService
             // and NetworkPolicyManager because ConnectivityService needs to take these
             // services to initialize.
-            // TODO: Dynamically load service-connectivity.jar by using startServiceFromJar.
-            mSystemServiceManager.startService(CONNECTIVITY_SERVICE_INITIALIZER_CLASS);
+            mSystemServiceManager.startServiceFromJar(CONNECTIVITY_SERVICE_INITIALIZER_CLASS,
+                    CONNECTIVITY_SERVICE_APEX_PATH);
             connectivity = IConnectivityManager.Stub.asInterface(
                     ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
             // TODO: Use ConnectivityManager instead of ConnectivityService.
diff --git a/services/people/java/com/android/server/people/PeopleService.java b/services/people/java/com/android/server/people/PeopleService.java
index 49a41f0..16b9165 100644
--- a/services/people/java/com/android/server/people/PeopleService.java
+++ b/services/people/java/com/android/server/people/PeopleService.java
@@ -19,7 +19,9 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.app.ActivityManager;
 import android.app.people.ConversationChannel;
+import android.app.people.ConversationStatus;
 import android.app.people.IPeopleManager;
 import android.app.prediction.AppPredictionContext;
 import android.app.prediction.AppPredictionSessionId;
@@ -27,6 +29,7 @@
 import android.app.prediction.AppTargetEvent;
 import android.app.prediction.IPredictionCallback;
 import android.content.Context;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.ParceledListSlice;
 import android.os.Binder;
 import android.os.CancellationSignal;
@@ -38,9 +41,11 @@
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.people.data.DataManager;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.function.Consumer;
@@ -54,6 +59,8 @@
 
     private final DataManager mDataManager;
 
+    private PackageManagerInternal mPackageManagerInternal;
+
     /**
      * Initializes the system service.
      *
@@ -83,6 +90,7 @@
             publishBinderService(Context.PEOPLE_SERVICE, mService);
         }
         publishLocalService(PeopleServiceInternal.class, new LocalService());
+        mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
     }
 
     @Override
@@ -112,6 +120,26 @@
         return UserHandle.isSameApp(uid, Process.SYSTEM_UID) || uid == Process.ROOT_UID;
     }
 
+    private int handleIncomingUser(int userId) {
+        try {
+            return ActivityManager.getService().handleIncomingUser(
+                    Binder.getCallingPid(), Binder.getCallingUid(), userId, true, true, "", null);
+        } catch (RemoteException re) {
+            // Shouldn't happen, local.
+        }
+        return userId;
+    }
+
+    private void checkCallerIsSameApp(String pkg) {
+        final int callingUid = Binder.getCallingUid();
+        final int callingUserId = UserHandle.getUserId(callingUid);
+
+        if (mPackageManagerInternal.getPackageUid(pkg, /*flags=*/ 0,
+                callingUserId) != callingUid) {
+            throw new SecurityException("Calling uid " + callingUid + " cannot query events"
+                    + "for package " + pkg);
+        }
+    }
 
     /**
      * Enforces that only the system, root UID or SystemUI can make certain calls.
@@ -154,6 +182,40 @@
             enforceSystemRootOrSystemUI(getContext(), "get last interaction");
             return mDataManager.getLastInteraction(packageName, userId, shortcutId);
         }
+
+        @Override
+        public void addOrUpdateStatus(String packageName, int userId, String conversationId,
+                ConversationStatus status) {
+            handleIncomingUser(userId);
+            checkCallerIsSameApp(packageName);
+            mDataManager.addOrUpdateStatus(packageName, userId, conversationId, status);
+        }
+
+        @Override
+        public void clearStatus(String packageName, int userId, String conversationId,
+                String statusId) {
+            handleIncomingUser(userId);
+            checkCallerIsSameApp(packageName);
+            mDataManager.clearStatus(packageName, userId, conversationId, statusId);
+        }
+
+        @Override
+        public void clearStatuses(String packageName, int userId, String conversationId) {
+            handleIncomingUser(userId);
+            checkCallerIsSameApp(packageName);
+            mDataManager.clearStatuses(packageName, userId, conversationId);
+        }
+
+        @Override
+        public ParceledListSlice<ConversationStatus> getStatuses(String packageName, int userId,
+                String conversationId) {
+            handleIncomingUser(userId);
+            if (!isSystemOrRoot()) {
+                checkCallerIsSameApp(packageName);
+            }
+            return new ParceledListSlice<>(
+                    mDataManager.getStatuses(packageName, userId, conversationId));
+        }
     };
 
     @VisibleForTesting
diff --git a/services/people/java/com/android/server/people/data/ConversationInfo.java b/services/people/java/com/android/server/people/data/ConversationInfo.java
index 45f389c..16c4c29 100644
--- a/services/people/java/com/android/server/people/data/ConversationInfo.java
+++ b/services/people/java/com/android/server/people/data/ConversationInfo.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.people.ConversationStatus;
 import android.content.LocusId;
 import android.content.LocusIdProto;
 import android.content.pm.ShortcutInfo;
@@ -39,6 +40,10 @@
 import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 
 /**
@@ -101,6 +106,8 @@
     @ConversationFlags
     private int mConversationFlags;
 
+    private Map<String, ConversationStatus> mCurrStatuses;
+
     private ConversationInfo(Builder builder) {
         mShortcutId = builder.mShortcutId;
         mLocusId = builder.mLocusId;
@@ -111,6 +118,7 @@
         mLastEventTimestamp = builder.mLastEventTimestamp;
         mShortcutFlags = builder.mShortcutFlags;
         mConversationFlags = builder.mConversationFlags;
+        mCurrStatuses = builder.mCurrStatuses;
     }
 
     @NonNull
@@ -213,6 +221,10 @@
         return hasConversationFlags(FLAG_CONTACT_STARRED);
     }
 
+    public Collection<ConversationStatus> getStatuses() {
+        return mCurrStatuses.values();
+    }
+
     @Override
     public boolean equals(Object obj) {
         if (this == obj) {
@@ -230,14 +242,15 @@
                 && Objects.equals(mParentNotificationChannelId, other.mParentNotificationChannelId)
                 && Objects.equals(mLastEventTimestamp, other.mLastEventTimestamp)
                 && mShortcutFlags == other.mShortcutFlags
-                && mConversationFlags == other.mConversationFlags;
+                && mConversationFlags == other.mConversationFlags
+                && Objects.equals(mCurrStatuses, other.mCurrStatuses);
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(mShortcutId, mLocusId, mContactUri, mContactPhoneNumber,
                 mNotificationChannelId, mParentNotificationChannelId, mLastEventTimestamp,
-                mShortcutFlags, mConversationFlags);
+                mShortcutFlags, mConversationFlags, mCurrStatuses);
     }
 
     @Override
@@ -251,6 +264,7 @@
         sb.append(", notificationChannelId=").append(mNotificationChannelId);
         sb.append(", parentNotificationChannelId=").append(mParentNotificationChannelId);
         sb.append(", lastEventTimestamp=").append(mLastEventTimestamp);
+        sb.append(", statuses=").append(mCurrStatuses);
         sb.append(", shortcutFlags=0x").append(Integer.toHexString(mShortcutFlags));
         sb.append(" [");
         if (isShortcutLongLived()) {
@@ -321,6 +335,7 @@
             protoOutputStream.write(ConversationInfoProto.CONTACT_PHONE_NUMBER,
                     mContactPhoneNumber);
         }
+        // ConversationStatus is a transient object and not persisted
     }
 
     @Nullable
@@ -337,6 +352,7 @@
             out.writeUTF(mContactPhoneNumber != null ? mContactPhoneNumber : "");
             out.writeUTF(mParentNotificationChannelId != null ? mParentNotificationChannelId : "");
             out.writeLong(mLastEventTimestamp);
+            // ConversationStatus is a transient object and not persisted
         } catch (IOException e) {
             Slog.e(TAG, "Failed to write fields to backup payload.", e);
             return null;
@@ -469,6 +485,8 @@
         @ConversationFlags
         private int mConversationFlags;
 
+        private Map<String, ConversationStatus> mCurrStatuses = new HashMap<>();
+
         Builder() {
         }
 
@@ -486,6 +504,7 @@
             mLastEventTimestamp = conversationInfo.mLastEventTimestamp;
             mShortcutFlags = conversationInfo.mShortcutFlags;
             mConversationFlags = conversationInfo.mConversationFlags;
+            mCurrStatuses = conversationInfo.mCurrStatuses;
         }
 
         Builder setShortcutId(@NonNull String shortcutId) {
@@ -579,6 +598,26 @@
             return this;
         }
 
+        Builder setStatuses(List<ConversationStatus> statuses) {
+            mCurrStatuses.clear();
+            if (statuses != null) {
+                for (ConversationStatus status : statuses) {
+                    mCurrStatuses.put(status.getId(), status);
+                }
+            }
+            return this;
+        }
+
+        Builder addOrUpdateStatus(ConversationStatus status) {
+            mCurrStatuses.put(status.getId(), status);
+            return this;
+        }
+
+        Builder clearStatus(String statusId) {
+            mCurrStatuses.remove(statusId);
+            return this;
+        }
+
         ConversationInfo build() {
             Objects.requireNonNull(mShortcutId);
             return new ConversationInfo(this);
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index b5e595a..e04e287 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -26,6 +26,7 @@
 import android.app.NotificationManager;
 import android.app.Person;
 import android.app.people.ConversationChannel;
+import android.app.people.ConversationStatus;
 import android.app.prediction.AppTarget;
 import android.app.prediction.AppTargetEvent;
 import android.app.usage.UsageEvents;
@@ -75,6 +76,7 @@
 import com.android.server.notification.ShortcutHelper;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashSet;
@@ -308,6 +310,73 @@
         return 0L;
     }
 
+    public void addOrUpdateStatus(String packageName, int userId, String conversationId,
+            ConversationStatus status) {
+        ConversationStore cs = getConversationStoreOrThrow(packageName, userId);
+        ConversationInfo convToModify = getConversationInfoOrThrow(cs, conversationId);
+        ConversationInfo.Builder builder = new ConversationInfo.Builder(convToModify);
+        builder.addOrUpdateStatus(status);
+        cs.addOrUpdate(builder.build());
+    }
+
+    public void clearStatus(String packageName, int userId, String conversationId,
+            String statusId) {
+        ConversationStore cs = getConversationStoreOrThrow(packageName, userId);
+        ConversationInfo convToModify = getConversationInfoOrThrow(cs, conversationId);
+        ConversationInfo.Builder builder = new ConversationInfo.Builder(convToModify);
+        builder.clearStatus(statusId);
+        cs.addOrUpdate(builder.build());
+    }
+
+    public void clearStatuses(String packageName, int userId, String conversationId) {
+        ConversationStore cs = getConversationStoreOrThrow(packageName, userId);
+        ConversationInfo convToModify = getConversationInfoOrThrow(cs, conversationId);
+        ConversationInfo.Builder builder = new ConversationInfo.Builder(convToModify);
+        builder.setStatuses(null);
+        cs.addOrUpdate(builder.build());
+    }
+
+    public @NonNull List<ConversationStatus> getStatuses(String packageName, int userId,
+            String conversationId) {
+        ConversationStore cs = getConversationStoreOrThrow(packageName, userId);
+        ConversationInfo conversationInfo = getConversationInfoOrThrow(cs, conversationId);
+        Collection<ConversationStatus> statuses = conversationInfo.getStatuses();
+        if (statuses != null) {
+            final ArrayList<ConversationStatus> list = new ArrayList<>(statuses.size());
+            list.addAll(statuses);
+            return list;
+        }
+        return new ArrayList<>();
+    }
+
+    /**
+     * Returns a conversation store for a package, if it exists.
+     */
+    private @NonNull ConversationStore getConversationStoreOrThrow(String packageName, int userId) {
+        final PackageData packageData = getPackage(packageName, userId);
+        if (packageData == null) {
+            throw new IllegalArgumentException("No settings exist for package " + packageName);
+        }
+        ConversationStore cs = packageData.getConversationStore();
+        if (cs == null) {
+            throw new IllegalArgumentException("No conversations exist for package " + packageName);
+        }
+        return cs;
+    }
+
+    /**
+     * Returns a conversation store for a package, if it exists.
+     */
+    private @NonNull ConversationInfo getConversationInfoOrThrow(ConversationStore cs,
+            String conversationId) {
+        ConversationInfo ci = cs.getConversation(conversationId);
+
+        if (ci == null) {
+            throw new IllegalArgumentException("Conversation does not exist");
+        }
+        return ci;
+    }
+
     /** Reports the sharing related {@link AppTargetEvent} from App Prediction Manager. */
     public void reportShareTargetEvent(@NonNull AppTargetEvent event,
             @NonNull IntentFilter intentFilter) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/OWNERS b/services/tests/mockingservicestests/src/com/android/server/OWNERS
index e779e21..c0f0ce0 100644
--- a/services/tests/mockingservicestests/src/com/android/server/OWNERS
+++ b/services/tests/mockingservicestests/src/com/android/server/OWNERS
@@ -1 +1,3 @@
 per-file *Alarm* = file:/apex/jobscheduler/OWNERS
+per-file *AppStateTracker* = file:/apex/jobscheduler/OWNERS
+per-file *DeviceIdleController* = file:/apex/jobscheduler/OWNERS
diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
index f375421..fd364ae7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
@@ -233,8 +233,10 @@
                 verifiedTimesMap);
 
         noteBoot(4);
+        assertTrue(RescueParty.isRebootPropertySet());
 
-        assertTrue(RescueParty.isAttemptingFactoryReset());
+        noteBoot(5);
+        assertTrue(RescueParty.isFactoryResetPropertySet());
     }
 
     @Test
@@ -255,7 +257,10 @@
                 /*configResetVerifiedTimesMap=*/ null);
 
         notePersistentAppCrash(4);
-        assertTrue(RescueParty.isAttemptingFactoryReset());
+        assertTrue(RescueParty.isRebootPropertySet());
+
+        notePersistentAppCrash(5);
+        assertTrue(RescueParty.isFactoryResetPropertySet());
     }
 
     @Test
@@ -306,7 +311,11 @@
 
         observer.execute(new VersionedPackage(
                 CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 4);
-        assertTrue(RescueParty.isAttemptingFactoryReset());
+        assertTrue(RescueParty.isRebootPropertySet());
+
+        observer.execute(new VersionedPackage(
+                CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 5);
+        assertTrue(RescueParty.isFactoryResetPropertySet());
     }
 
     @Test
@@ -367,7 +376,11 @@
 
         observer.execute(new VersionedPackage(
                 CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 4);
-        assertTrue(RescueParty.isAttemptingFactoryReset());
+        assertTrue(RescueParty.isRebootPropertySet());
+
+        observer.execute(new VersionedPackage(
+                CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 5);
+        assertTrue(RescueParty.isFactoryResetPropertySet());
     }
 
     @Test
@@ -376,6 +389,7 @@
             noteBoot(i + 1);
         }
         assertTrue(RescueParty.isAttemptingFactoryReset());
+        assertTrue(RescueParty.isFactoryResetPropertySet());
     }
 
     @Test
@@ -424,7 +438,7 @@
         for (int i = 0; i < LEVEL_FACTORY_RESET; i++) {
             noteBoot(i + 1);
         }
-        assertFalse(RescueParty.isAttemptingFactoryReset());
+        assertFalse(RescueParty.isFactoryResetPropertySet());
 
         // Restore the property value initialized in SetUp()
         SystemProperties.set(PROP_DISABLE_FACTORY_RESET_FLAG, "");
diff --git a/services/tests/servicestests/src/com/android/server/apphibernation/OWNERS b/services/tests/servicestests/src/com/android/server/apphibernation/OWNERS
new file mode 100644
index 0000000..c2e27e0
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/apphibernation/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/apphibernation/OWNERS
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 f29b059..c6fde87 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
@@ -22,10 +22,12 @@
 
 import android.app.appsearch.AppSearchSchema;
 import android.app.appsearch.GenericDocument;
+import android.app.appsearch.SearchResult;
 import android.app.appsearch.SearchResultPage;
 import android.app.appsearch.SearchSpec;
 import android.app.appsearch.exceptions.AppSearchException;
 
+import com.android.server.appsearch.external.localstorage.converter.GenericDocumentToProtoConverter;
 import com.android.server.appsearch.external.localstorage.converter.SchemaToProtoConverter;
 import com.android.server.appsearch.proto.DocumentProto;
 import com.android.server.appsearch.proto.GetOptimizeInfoResultProto;
@@ -33,6 +35,7 @@
 import com.android.server.appsearch.proto.PropertyProto;
 import com.android.server.appsearch.proto.SchemaProto;
 import com.android.server.appsearch.proto.SchemaTypeConfigProto;
+import com.android.server.appsearch.proto.SearchResultProto;
 import com.android.server.appsearch.proto.SearchSpecProto;
 import com.android.server.appsearch.proto.StringIndexingConfig;
 import com.android.server.appsearch.proto.TermMatchType;
@@ -316,14 +319,14 @@
         DocumentProto insideDocument =
                 DocumentProto.newBuilder()
                         .setUri("inside-uri")
-                        .setSchema("package$databaseName1/type")
-                        .setNamespace("package$databaseName2/namespace")
+                        .setSchema("package$databaseName/type")
+                        .setNamespace("package$databaseName/namespace")
                         .build();
         DocumentProto documentProto =
                 DocumentProto.newBuilder()
                         .setUri("uri")
-                        .setSchema("package$databaseName2/type")
-                        .setNamespace("package$databaseName3/namespace")
+                        .setSchema("package$databaseName/type")
+                        .setNamespace("package$databaseName/namespace")
                         .addProperties(PropertyProto.newBuilder().addDocumentValues(insideDocument))
                         .build();
 
@@ -345,11 +348,56 @@
                         .build();
 
         DocumentProto.Builder actualDocument = documentProto.toBuilder();
-        mAppSearchImpl.removePrefixesFromDocument(actualDocument);
+        assertThat(mAppSearchImpl.removePrefixesFromDocument(actualDocument))
+                .isEqualTo("package$databaseName/");
         assertThat(actualDocument.build()).isEqualTo(expectedDocumentProto);
     }
 
     @Test
+    public void testRemoveDatabasesFromDocumentThrowsException() throws Exception {
+        // Set two different database names in the document, which should never happen
+        DocumentProto documentProto =
+                DocumentProto.newBuilder()
+                        .setUri("uri")
+                        .setSchema("prefix1/type")
+                        .setNamespace("prefix2/namespace")
+                        .build();
+
+        DocumentProto.Builder actualDocument = documentProto.toBuilder();
+        AppSearchException e =
+                expectThrows(
+                        AppSearchException.class,
+                        () -> mAppSearchImpl.removePrefixesFromDocument(actualDocument));
+        assertThat(e).hasMessageThat().contains("Found unexpected multiple prefix names");
+    }
+
+    @Test
+    public void testNestedRemoveDatabasesFromDocumentThrowsException() throws Exception {
+        // Set two different database names in the outer and inner document, which should never
+        // happen.
+        DocumentProto insideDocument =
+                DocumentProto.newBuilder()
+                        .setUri("inside-uri")
+                        .setSchema("prefix1/type")
+                        .setNamespace("prefix1/namespace")
+                        .build();
+        DocumentProto documentProto =
+                DocumentProto.newBuilder()
+                        .setUri("uri")
+                        .setSchema("prefix2/type")
+                        .setNamespace("prefix2/namespace")
+                        .addProperties(PropertyProto.newBuilder().addDocumentValues(insideDocument))
+                        .build();
+
+        DocumentProto.Builder actualDocument = documentProto.toBuilder();
+        AppSearchException e =
+                expectThrows(
+                        AppSearchException.class,
+                        () -> mAppSearchImpl.removePrefixesFromDocument(actualDocument));
+        assertThat(e).hasMessageThat().contains("Found unexpected multiple prefix names");
+    }
+
+    @Test
     public void testOptimize() throws Exception {
         // Insert schema
         List<AppSearchSchema> schemas =
@@ -865,4 +913,40 @@
                         AppSearchImpl.createPrefix("package", "database1"),
                         AppSearchImpl.createPrefix("package", "database2"));
     }
+
+    @Test
+    public void testRewriteSearchResultProto() throws Exception {
+        final String database =
+                "com.package.foo"
+                        + AppSearchImpl.PACKAGE_DELIMITER
+                        + "databaseName"
+                        + AppSearchImpl.DATABASE_DELIMITER;
+        final String uri = "uri";
+        final String namespace = database + "namespace";
+        final String schemaType = database + "schema";
+
+        // Building the SearchResult received from query.
+        DocumentProto documentProto =
+                DocumentProto.newBuilder()
+                        .setUri(uri)
+                        .setNamespace(namespace)
+                        .setSchema(schemaType)
+                        .build();
+        SearchResultProto.ResultProto resultProto =
+                SearchResultProto.ResultProto.newBuilder().setDocument(documentProto).build();
+        SearchResultProto searchResultProto =
+                SearchResultProto.newBuilder().addResults(resultProto).build();
+
+        DocumentProto.Builder strippedDocumentProto = documentProto.toBuilder();
+        AppSearchImpl.removePrefixesFromDocument(strippedDocumentProto);
+        SearchResultPage searchResultPage =
+                AppSearchImpl.rewriteSearchResultProto(searchResultProto);
+        for (SearchResult result : searchResultPage.getResults()) {
+            assertThat(result.getPackageName()).isEqualTo("com.package.foo");
+            assertThat(result.getDocument())
+                    .isEqualTo(
+                            GenericDocumentToProtoConverter.toGenericDocument(
+                                    strippedDocumentProto.build()));
+        }
+    }
 }
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 7c68c6b..a3f0f6b 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
@@ -29,6 +29,8 @@
 
 import org.junit.Test;
 
+import java.util.Collections;
+
 public class SnippetTest {
 
     // TODO(tytytyww): Add tests for Double and Long Snippets.
@@ -83,7 +85,8 @@
 
         // Making ResultReader and getting Snippet values.
         SearchResultPage searchResultPage =
-                SearchResultToProtoConverter.toSearchResultPage(searchResultProto);
+                SearchResultToProtoConverter.toSearchResultPage(
+                        searchResultProto, Collections.singletonList("packageName"));
         for (SearchResult result : searchResultPage.getResults()) {
             SearchResult.MatchInfo match = result.getMatches().get(0);
             assertThat(match.getPropertyPath()).isEqualTo(propertyKeyString);
@@ -131,7 +134,8 @@
                 SearchResultProto.newBuilder().addResults(resultProto).build();
 
         SearchResultPage searchResultPage =
-                SearchResultToProtoConverter.toSearchResultPage(searchResultProto);
+                SearchResultToProtoConverter.toSearchResultPage(
+                        searchResultProto, Collections.singletonList("packageName"));
         for (SearchResult result : searchResultPage.getResults()) {
             assertThat(result.getMatches()).isEmpty();
         }
@@ -196,7 +200,8 @@
 
         // Making ResultReader and getting Snippet values.
         SearchResultPage searchResultPage =
-                SearchResultToProtoConverter.toSearchResultPage(searchResultProto);
+                SearchResultToProtoConverter.toSearchResultPage(
+                        searchResultProto, Collections.singletonList("packageName"));
         for (SearchResult result : searchResultPage.getResults()) {
 
             SearchResult.MatchInfo match1 = result.getMatches().get(0);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 17324ba..9c28c99 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -460,6 +460,11 @@
         }
 
         @Override
+        KeyChain.KeyChainConnection keyChainBind() {
+            return services.keyChainConnection;
+        }
+
+        @Override
         KeyChain.KeyChainConnection keyChainBindAsUser(UserHandle user) {
             return services.keyChainConnection;
         }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index c1b1133..39fa20e 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -1628,6 +1628,33 @@
                 )), eq(user));
     }
 
+    @Test
+    public void testRemoveCredentialManagementApp() throws Exception {
+        final String packageName = "com.test.cred.mng";
+        Intent intent = new Intent(Intent.ACTION_PACKAGE_REMOVED);
+        intent.setData(Uri.parse("package:" + packageName));
+        dpms.mReceiver.setPendingResult(
+                new BroadcastReceiver.PendingResult(Activity.RESULT_OK,
+                        "resultData",
+                        /* resultExtras= */ null,
+                        BroadcastReceiver.PendingResult.TYPE_UNREGISTERED,
+                        /* ordered= */ true,
+                        /* sticky= */ false,
+                        /* token= */ null,
+                        CALLER_USER_HANDLE,
+                        /* flags= */ 0));
+        when(getServices().keyChainConnection.getService().hasCredentialManagementApp())
+                .thenReturn(true);
+        when(getServices().keyChainConnection.getService().getCredentialManagementAppPackageName())
+                .thenReturn(packageName);
+
+        dpms.mReceiver.onReceive(mContext, intent);
+
+        flushTasks(dpms);
+        verify(getServices().keyChainConnection.getService()).hasCredentialManagementApp();
+        verify(getServices().keyChainConnection.getService()).removeCredentialManagementApp();
+    }
+
     /**
      * Simple test for delegate set/get and general delegation. Tests verifying that delegated
      * privileges can acually be exercised by a delegate are not covered here.
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/EnterpriseSpecificIdCalculatorTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/EnterpriseSpecificIdCalculatorTest.java
new file mode 100644
index 0000000..c2c1d5b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/EnterpriseSpecificIdCalculatorTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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.devicepolicy;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class EnterpriseSpecificIdCalculatorTest {
+    private static final String SOME_IMEI = "56134231542345";
+    private static final String SOME_SERIAL_NUMBER = "XZ663CCAJA7";
+    private static final String SOME_MAC_ADDRESS = "65:ca:f3:fe:9d:b1";
+    private static final String NO_MEID = null;
+    private static final String SOME_PACKAGE = "com.example.test.dpc";
+    private static final String ANOTHER_PACKAGE = "org.example.test.another.dpc";
+    private static final String SOME_ENTERPRISE_ID = "73456234";
+    private static final String ANOTHER_ENTERPRISE_ID = "243441";
+
+    private EnterpriseSpecificIdCalculator mEsidCalculator;
+
+    @Before
+    public void createDefaultEsidCalculator() {
+        mEsidCalculator = new EnterpriseSpecificIdCalculator(SOME_IMEI, NO_MEID, SOME_SERIAL_NUMBER,
+                SOME_MAC_ADDRESS);
+    }
+
+    @Test
+    public void paddingOfIdentifiers() {
+        assertThat(mEsidCalculator.getPaddedImei()).isEqualTo("  56134231542345");
+        assertThat(mEsidCalculator.getPaddedMeid()).isEqualTo("                ");
+        assertThat(mEsidCalculator.getPaddedSerialNumber()).isEqualTo("     XZ663CCAJA7");
+    }
+
+    @Test
+    public void truncationOfLongIdentifier() {
+        EnterpriseSpecificIdCalculator esidCalculator = new EnterpriseSpecificIdCalculator(
+                SOME_IMEI, NO_MEID, "XZ663CCAJA7XZ663CCAJA7XZ663CCAJA7",
+                SOME_MAC_ADDRESS);
+        assertThat(esidCalculator.getPaddedSerialNumber()).isEqualTo("XZ663CCAJA7XZ663");
+    }
+
+    @Test
+    public void paddingOfPackageName() {
+        assertThat(mEsidCalculator.getPaddedProfileOwnerName(SOME_PACKAGE)).isEqualTo(
+                "                                            " + SOME_PACKAGE);
+    }
+
+    @Test
+    public void paddingOfEnterpriseId() {
+        assertThat(mEsidCalculator.getPaddedEnterpriseId(SOME_ENTERPRISE_ID)).isEqualTo(
+                "                                                        " + SOME_ENTERPRISE_ID);
+    }
+
+    @Test
+    public void emptyEnterpriseIdYieldsEmptyEsid() {
+        assertThrows(IllegalArgumentException.class, () ->
+                mEsidCalculator.calculateEnterpriseId(SOME_PACKAGE, ""));
+    }
+
+    @Test
+    public void emptyDpcPackageYieldsEmptyEsid() {
+        assertThrows(IllegalArgumentException.class, () ->
+                mEsidCalculator.calculateEnterpriseId("", SOME_ENTERPRISE_ID));
+    }
+
+    // On upgrade, an ESID will be calculated with an empty Enterprise ID. This is signalled
+    // to the EnterpriseSpecificIdCalculator by passing in null.
+    @Test
+    public void nullEnterpriseIdYieldsValidEsid() {
+        assertThat(mEsidCalculator.calculateEnterpriseId(SOME_PACKAGE, null)).isEqualTo(
+                "C4W7-VUJT-PHSA-HMY53-CLHX-L4HW-L");
+    }
+
+    @Test
+    public void knownValues() {
+        assertThat(
+                mEsidCalculator.calculateEnterpriseId(SOME_PACKAGE, SOME_ENTERPRISE_ID)).isEqualTo(
+                "FP7B-RXQW-Q77F-7J6FC-5RXZ-UJI6-6");
+        assertThat(mEsidCalculator.calculateEnterpriseId(SOME_PACKAGE,
+                ANOTHER_ENTERPRISE_ID)).isEqualTo("ATAL-VPIX-GBNZ-NE3TF-TDEV-3OVO-C");
+        assertThat(mEsidCalculator.calculateEnterpriseId(ANOTHER_PACKAGE,
+                SOME_ENTERPRISE_ID)).isEqualTo("JHU3-6SHH-YLHC-ZGETD-PWNI-7NPQ-S");
+        assertThat(mEsidCalculator.calculateEnterpriseId(ANOTHER_PACKAGE,
+                ANOTHER_ENTERPRISE_ID)).isEqualTo("LEF3-QBEC-UQ6O-RIOCX-TQF6-GRLV-F");
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/graphics/fonts/OWNERS b/services/tests/servicestests/src/com/android/server/graphics/fonts/OWNERS
new file mode 100644
index 0000000..34ac813
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/graphics/fonts/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 24939
+
+include /graphics/java/android/graphics/fonts/OWNERS
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 be8e569..99ecb86 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;
 
@@ -131,6 +132,7 @@
     }
 
     @Test
+    @FlakyTest
     public void testPowerWhiteList() throws Exception {
         scheduleAndAssertJobStarted();
         setAppOpsModeAllowed(false);
diff --git a/services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java b/services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java
index 5cff208..972b3bb 100644
--- a/services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java
@@ -89,6 +89,81 @@
     }
 
     @Test
+    public void initializationFailure_primary() {
+        ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
+                mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
+        TestEnvironment testEnvironment = new TestEnvironment(
+                mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        Duration expectedInitTimeout = testEnvironment.getProviderInitializationTimeout()
+                .plus(testEnvironment.getProviderInitializationTimeoutFuzz());
+
+        mTestPrimaryLocationTimeZoneProvider.setFailDuringInitialization(true);
+
+        // Initialize. After initialization the providers must be initialized and one should be
+        // started.
+        controllerImpl.initialize(testEnvironment, mTestCallback);
+
+        mTestPrimaryLocationTimeZoneProvider.assertInitialized();
+        mTestSecondaryLocationTimeZoneProvider.assertInitialized();
+
+        mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+        mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestSecondaryLocationTimeZoneProvider.assertInitializationTimeoutSet(expectedInitTimeout);
+        mTestCallback.assertNoSuggestionMade();
+        assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+    }
+
+    @Test
+    public void initializationFailure_secondary() {
+        ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
+                mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
+        TestEnvironment testEnvironment = new TestEnvironment(
+                mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        Duration expectedInitTimeout = testEnvironment.getProviderInitializationTimeout()
+                .plus(testEnvironment.getProviderInitializationTimeoutFuzz());
+
+        mTestSecondaryLocationTimeZoneProvider.setFailDuringInitialization(true);
+
+        // Initialize. After initialization the providers must be initialized and one should be
+        // started.
+        controllerImpl.initialize(testEnvironment, mTestCallback);
+
+        mTestPrimaryLocationTimeZoneProvider.assertInitialized();
+        mTestSecondaryLocationTimeZoneProvider.assertInitialized();
+
+        mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
+                PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
+        mTestPrimaryLocationTimeZoneProvider.assertInitializationTimeoutSet(expectedInitTimeout);
+        mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+        mTestCallback.assertNoSuggestionMade();
+        assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+    }
+
+    @Test
+    public void initializationFailure_both() {
+        ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
+                mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
+        TestEnvironment testEnvironment = new TestEnvironment(
+                mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
+
+        mTestPrimaryLocationTimeZoneProvider.setFailDuringInitialization(true);
+        mTestSecondaryLocationTimeZoneProvider.setFailDuringInitialization(true);
+
+        // Initialize. After initialization the providers must be initialized and one should be
+        // started.
+        controllerImpl.initialize(testEnvironment, mTestCallback);
+
+        mTestPrimaryLocationTimeZoneProvider.assertInitialized();
+        mTestSecondaryLocationTimeZoneProvider.assertInitialized();
+
+        mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+        mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
+        mTestCallback.assertUncertainSuggestionMadeAndCommit();
+        assertFalse(controllerImpl.isUncertaintyTimeoutSet());
+    }
+
+    @Test
     public void initialState_started() {
         ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
                 mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
@@ -1097,6 +1172,7 @@
 
         /** Used to track historic provider states for tests. */
         private final TestState<ProviderState> mTestProviderState = new TestState<>();
+        private boolean mFailDuringInitialization;
         private boolean mInitialized;
         private boolean mDestroyed;
 
@@ -1107,9 +1183,16 @@
             super(threadingDomain, providerName);
         }
 
+        public void setFailDuringInitialization(boolean failInitialization) {
+            mFailDuringInitialization = failInitialization;
+        }
+
         @Override
         void onInitialize() {
             mInitialized = true;
+            if (mFailDuringInitialization) {
+                throw new RuntimeException("Simulated initialization failure");
+            }
         }
 
         @Override
diff --git a/services/tests/servicestests/src/com/android/server/net/watchlist/NetworkWatchlistServiceTests.java b/services/tests/servicestests/src/com/android/server/net/watchlist/NetworkWatchlistServiceTests.java
index 9c8a382..ac9316e 100644
--- a/services/tests/servicestests/src/com/android/server/net/watchlist/NetworkWatchlistServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/net/watchlist/NetworkWatchlistServiceTests.java
@@ -24,6 +24,9 @@
 import android.net.ConnectivityMetricsEvent;
 import android.net.IIpConnectivityMetrics;
 import android.net.INetdEventCallback;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
@@ -106,6 +109,16 @@
             counter--;
             return true;
         }
+
+        // TODO: mark @Override when aosp/1541935 automerges to master.
+        public void logDefaultNetworkValidity(boolean valid) {
+        }
+
+        // TODO: mark @Override when aosp/1541935 automerges to master.
+        public void logDefaultNetworkEvent(Network defaultNetwork, int score, boolean validated,
+                LinkProperties lp, NetworkCapabilities nc, Network previousDefaultNetwork,
+                int previousScore, LinkProperties previousLp, NetworkCapabilities previousNc) {
+        }
     };
 
     ServiceThread mHandlerThread;
diff --git a/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java b/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java
index c6823eb..8139310 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java
@@ -16,11 +16,17 @@
 
 package com.android.server.people.data;
 
+import static android.app.people.ConversationStatus.ACTIVITY_ANNIVERSARY;
+import static android.app.people.ConversationStatus.ACTIVITY_GAME;
+
+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.assertNull;
 import static org.junit.Assert.assertTrue;
 
+import android.app.people.ConversationStatus;
 import android.content.LocusId;
 import android.content.pm.ShortcutInfo;
 import android.net.Uri;
@@ -41,6 +47,9 @@
 
     @Test
     public void testBuild() {
+        ConversationStatus cs = new ConversationStatus.Builder("id", ACTIVITY_ANNIVERSARY).build();
+        ConversationStatus cs2 = new ConversationStatus.Builder("id2", ACTIVITY_GAME).build();
+
         ConversationInfo conversationInfo = new ConversationInfo.Builder()
                 .setShortcutId(SHORTCUT_ID)
                 .setLocusId(LOCUS_ID)
@@ -58,6 +67,8 @@
                 .setPersonImportant(true)
                 .setPersonBot(true)
                 .setContactStarred(true)
+                .addOrUpdateStatus(cs)
+                .addOrUpdateStatus(cs2)
                 .build();
 
         assertEquals(SHORTCUT_ID, conversationInfo.getShortcutId());
@@ -77,6 +88,8 @@
         assertTrue(conversationInfo.isPersonImportant());
         assertTrue(conversationInfo.isPersonBot());
         assertTrue(conversationInfo.isContactStarred());
+        assertThat(conversationInfo.getStatuses()).contains(cs);
+        assertThat(conversationInfo.getStatuses()).contains(cs2);
     }
 
     @Test
@@ -101,10 +114,15 @@
         assertFalse(conversationInfo.isPersonImportant());
         assertFalse(conversationInfo.isPersonBot());
         assertFalse(conversationInfo.isContactStarred());
+        assertThat(conversationInfo.getStatuses()).isNotNull();
+        assertThat(conversationInfo.getStatuses()).isEmpty();
     }
 
     @Test
     public void testBuildFromAnotherConversationInfo() {
+        ConversationStatus cs = new ConversationStatus.Builder("id", ACTIVITY_ANNIVERSARY).build();
+        ConversationStatus cs2 = new ConversationStatus.Builder("id2", ACTIVITY_GAME).build();
+
         ConversationInfo source = new ConversationInfo.Builder()
                 .setShortcutId(SHORTCUT_ID)
                 .setLocusId(LOCUS_ID)
@@ -120,6 +138,8 @@
                 .setPersonImportant(true)
                 .setPersonBot(true)
                 .setContactStarred(true)
+                .addOrUpdateStatus(cs)
+                .addOrUpdateStatus(cs2)
                 .build();
 
         ConversationInfo destination = new ConversationInfo.Builder(source)
@@ -141,5 +161,7 @@
         assertTrue(destination.isPersonImportant());
         assertTrue(destination.isPersonBot());
         assertFalse(destination.isContactStarred());
+        assertThat(destination.getStatuses()).contains(cs);
+        assertThat(destination.getStatuses()).contains(cs2);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
index 2471210..be8a99c 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.server.people.data;
 
+import static android.app.people.ConversationStatus.ACTIVITY_ANNIVERSARY;
+import static android.app.people.ConversationStatus.ACTIVITY_GAME;
 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
@@ -24,6 +26,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static junit.framework.Assert.fail;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -50,6 +54,7 @@
 import android.app.Person;
 import android.app.job.JobScheduler;
 import android.app.people.ConversationChannel;
+import android.app.people.ConversationStatus;
 import android.app.prediction.AppTarget;
 import android.app.prediction.AppTargetEvent;
 import android.app.prediction.AppTargetId;
@@ -937,6 +942,83 @@
     }
 
     @Test
+    public void testAddOrUpdateStatus_noCachedShortcut() {
+        mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+        ConversationStatus cs = new ConversationStatus.Builder("id", ACTIVITY_ANNIVERSARY).build();
+
+        try {
+            mDataManager.addOrUpdateStatus(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, cs);
+            fail("Updated a conversation info that didn't previously exist");
+        } catch (IllegalArgumentException e) {
+            // good
+        }
+    }
+
+    @Test
+    public void testAddOrUpdateStatus() {
+        mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+        ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+                buildPerson());
+        mDataManager.addOrUpdateConversationInfo(shortcut);
+
+        ConversationStatus cs = new ConversationStatus.Builder("id", ACTIVITY_ANNIVERSARY).build();
+        mDataManager.addOrUpdateStatus(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, cs);
+
+        assertThat(mDataManager.getStatuses(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID))
+                .contains(cs);
+
+        ConversationStatus cs2 = new ConversationStatus.Builder("id2", ACTIVITY_GAME).build();
+        mDataManager.addOrUpdateStatus(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, cs2);
+
+        assertThat(mDataManager.getStatuses(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID))
+                .contains(cs);
+        assertThat(mDataManager.getStatuses(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID))
+                .contains(cs2);
+    }
+
+    @Test
+    public void testClearStatus() {
+        mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+        ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+                buildPerson());
+        mDataManager.addOrUpdateConversationInfo(shortcut);
+
+        ConversationStatus cs = new ConversationStatus.Builder("id", ACTIVITY_ANNIVERSARY).build();
+        ConversationStatus cs2 = new ConversationStatus.Builder("id2", ACTIVITY_GAME).build();
+        mDataManager.addOrUpdateStatus(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, cs);
+        mDataManager.addOrUpdateStatus(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, cs2);
+
+        mDataManager.clearStatus(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, cs2.getId());
+
+        assertThat(mDataManager.getStatuses(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID))
+                .contains(cs);
+        assertThat(mDataManager.getStatuses(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID))
+                .doesNotContain(cs2);
+    }
+
+    @Test
+    public void testClearStatuses() {
+        mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+        ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+                buildPerson());
+        mDataManager.addOrUpdateConversationInfo(shortcut);
+
+        ConversationStatus cs = new ConversationStatus.Builder("id", ACTIVITY_ANNIVERSARY).build();
+        ConversationStatus cs2 = new ConversationStatus.Builder("id2", ACTIVITY_GAME).build();
+        mDataManager.addOrUpdateStatus(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, cs);
+        mDataManager.addOrUpdateStatus(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, cs2);
+
+        mDataManager.clearStatuses(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID);
+
+        assertThat(mDataManager.getStatuses(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID))
+                .isEmpty();
+    }
+
+    @Test
     public void testNonCachedShortcutNotInRecentList() {
         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
 
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 08d4caa..5f65440 100644
--- a/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
@@ -32,8 +32,13 @@
 
 import com.android.server.SystemService;
 import com.android.server.powerstats.PowerStatsHALWrapper.IPowerStatsHALWrapper;
+import com.android.server.powerstats.nano.PowerEntityInfoProto;
 import com.android.server.powerstats.nano.PowerStatsServiceMeterProto;
 import com.android.server.powerstats.nano.PowerStatsServiceModelProto;
+import com.android.server.powerstats.nano.PowerStatsServiceResidencyProto;
+import com.android.server.powerstats.nano.StateInfoProto;
+import com.android.server.powerstats.nano.StateResidencyProto;
+import com.android.server.powerstats.nano.StateResidencyResultProto;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -58,6 +63,7 @@
     private static final String DATA_STORAGE_SUBDIR = "powerstatstest";
     private static final String METER_FILENAME = "metertest";
     private static final String MODEL_FILENAME = "modeltest";
+    private static final String RESIDENCY_FILENAME = "residencytest";
     private static final String PROTO_OUTPUT_FILENAME = "powerstats.proto";
     private static final String CHANNEL_NAME = "channelname";
     private static final String POWER_ENTITY_NAME = "powerentityinfo";
@@ -72,6 +78,7 @@
     private PowerStatsService mService;
     private File mDataStorageDir;
     private TimerTrigger mTimerTrigger;
+    private BatteryTrigger mBatteryTrigger;
     private PowerStatsLogger mPowerStatsLogger;
 
     private final PowerStatsService.Injector mInjector = new PowerStatsService.Injector() {
@@ -99,22 +106,29 @@
         }
 
         @Override
+        String createResidencyFilename() {
+            return RESIDENCY_FILENAME;
+        }
+
+        @Override
         IPowerStatsHALWrapper createPowerStatsHALWrapperImpl() {
             return new TestPowerStatsHALWrapper();
         }
 
         @Override
         PowerStatsLogger createPowerStatsLogger(Context context, File dataStoragePath,
-                String meterFilename, String modelFilename,
+                String meterFilename, String modelFilename, String residencyFilename,
                 IPowerStatsHALWrapper powerStatsHALWrapper) {
             mPowerStatsLogger = new PowerStatsLogger(context, dataStoragePath, meterFilename,
-                modelFilename, powerStatsHALWrapper);
+                modelFilename, residencyFilename, powerStatsHALWrapper);
             return mPowerStatsLogger;
         }
 
         @Override
         BatteryTrigger createBatteryTrigger(Context context, PowerStatsLogger powerStatsLogger) {
-            return new BatteryTrigger(context, powerStatsLogger, false /* trigger enabled */);
+            mBatteryTrigger = new BatteryTrigger(context, powerStatsLogger,
+                false /* trigger enabled */);
+            return mBatteryTrigger;
         }
 
         @Override
@@ -137,7 +151,7 @@
                 for (int j = 0; j < powerEntityInfoList[i].states.length; j++) {
                     powerEntityInfoList[i].states[j] = new StateInfo();
                     powerEntityInfoList[i].states[j].stateId = j;
-                    powerEntityInfoList[i].states[j].stateName = new String(STATE_NAME + i);
+                    powerEntityInfoList[i].states[j].stateName = new String(STATE_NAME + j);
                 }
             }
             return powerEntityInfoList;
@@ -154,6 +168,7 @@
                     new StateResidency[STATE_RESIDENCY_COUNT];
                 for (int j = 0; j < stateResidencyResultList[i].stateResidencyData.length; j++) {
                     stateResidencyResultList[i].stateResidencyData[j] = new StateResidency();
+                    stateResidencyResultList[i].stateResidencyData[j].stateId = j;
                     stateResidencyResultList[i].stateResidencyData[j].totalTimeInStateMs = j;
                     stateResidencyResultList[i].stateResidencyData[j].totalStateEntryCount = j;
                     stateResidencyResultList[i].stateResidencyData[j].lastEntryTimestampMs = j;
@@ -225,7 +240,7 @@
         mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
 
         // Write data to on-device storage.
-        mTimerTrigger.logPowerStatsData();
+        mTimerTrigger.logPowerStatsData(PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE_TIMER);
 
         // The above call puts a message on a handler.  Wait for
         // it to be processed.
@@ -266,7 +281,7 @@
         mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
 
         // Write data to on-device storage.
-        mTimerTrigger.logPowerStatsData();
+        mTimerTrigger.logPowerStatsData(PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE_TIMER);
 
         // The above call puts a message on a handler.  Wait for
         // it to be processed.
@@ -301,6 +316,61 @@
     }
 
     @Test
+    public void testWrittenResidencyDataMatchesReadIncidentReportData()
+            throws InterruptedException, IOException {
+        mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
+
+        // Write data to on-device storage.
+        mBatteryTrigger.logPowerStatsData(PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE_BATTERY_DROP);
+
+        // The above call puts a message on a handler.  Wait for
+        // it to be processed.
+        Thread.sleep(100);
+
+        // Write on-device storage to an incident report.
+        File incidentReport = new File(mDataStorageDir, PROTO_OUTPUT_FILENAME);
+        FileOutputStream fos = new FileOutputStream(incidentReport);
+        mPowerStatsLogger.writeResidencyDataToFile(fos.getFD());
+
+        // Read the incident report in to a byte array.
+        FileInputStream fis = new FileInputStream(incidentReport);
+        byte[] fileContent = new byte[(int) incidentReport.length()];
+        fis.read(fileContent);
+
+        // Parse the incident data into a PowerStatsServiceResidencyProto object.
+        PowerStatsServiceResidencyProto pssProto =
+                PowerStatsServiceResidencyProto.parseFrom(fileContent);
+
+        // Validate the powerEntityInfo array matches what was written to on-device storage.
+        assertTrue(pssProto.powerEntityInfo.length == POWER_ENTITY_COUNT);
+        for (int i = 0; i < pssProto.powerEntityInfo.length; i++) {
+            PowerEntityInfoProto powerEntityInfo = pssProto.powerEntityInfo[i];
+            assertTrue(powerEntityInfo.powerEntityId == i);
+            assertTrue(powerEntityInfo.powerEntityName.equals(POWER_ENTITY_NAME + i));
+            for (int j = 0; j < powerEntityInfo.states.length; j++) {
+                StateInfoProto stateInfo = powerEntityInfo.states[j];
+                assertTrue(stateInfo.stateId == j);
+                assertTrue(stateInfo.stateName.equals(STATE_NAME + j));
+            }
+        }
+
+        // Validate the stateResidencyResult array matches what was written to on-device storage.
+        assertTrue(pssProto.stateResidencyResult.length == POWER_ENTITY_COUNT);
+        for (int i = 0; i < pssProto.stateResidencyResult.length; i++) {
+            StateResidencyResultProto stateResidencyResult = pssProto.stateResidencyResult[i];
+            assertTrue(stateResidencyResult.powerEntityId == i);
+            assertTrue(stateResidencyResult.stateResidencyData.length == STATE_RESIDENCY_COUNT);
+            for (int j = 0; j < stateResidencyResult.stateResidencyData.length; j++) {
+                StateResidencyProto stateResidency = stateResidencyResult.stateResidencyData[j];
+                assertTrue(stateResidency.stateId == j);
+                assertTrue(stateResidency.totalTimeInStateMs == j);
+                assertTrue(stateResidency.totalStateEntryCount == j);
+                assertTrue(stateResidency.lastEntryTimestampMs == j);
+            }
+        }
+    }
+
+    @Test
     public void testCorruptOnDeviceMeterStorage() throws IOException {
         mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
 
@@ -384,6 +454,55 @@
     }
 
     @Test
+    public void testCorruptOnDeviceResidencyStorage() throws IOException {
+        mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
+
+        // Generate random array of bytes to emulate corrupt data.
+        Random rd = new Random();
+        byte[] bytes = new byte[100];
+        rd.nextBytes(bytes);
+
+        // Store corrupt data in on-device storage.  Add fake timestamp to filename
+        // to match format expected by FileRotator.
+        File onDeviceStorageFile = new File(mDataStorageDir, RESIDENCY_FILENAME + ".1234-2234");
+        FileOutputStream onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile);
+        onDeviceStorageFos.write(bytes);
+        onDeviceStorageFos.close();
+
+        // Write on-device storage to an incident report.
+        File incidentReport = new File(mDataStorageDir, PROTO_OUTPUT_FILENAME);
+        FileOutputStream incidentReportFos = new FileOutputStream(incidentReport);
+        mPowerStatsLogger.writeResidencyDataToFile(incidentReportFos.getFD());
+
+        // Read the incident report in to a byte array.
+        FileInputStream fis = new FileInputStream(incidentReport);
+        byte[] fileContent = new byte[(int) incidentReport.length()];
+        fis.read(fileContent);
+
+        // Parse the incident data into a PowerStatsServiceResidencyProto object.
+        PowerStatsServiceResidencyProto pssProto =
+                PowerStatsServiceResidencyProto.parseFrom(fileContent);
+
+        // Valid powerEntityInfo data is written to the incident report in the call to
+        // mPowerStatsLogger.writeResidencyDataToFile().
+        assertTrue(pssProto.powerEntityInfo.length == POWER_ENTITY_COUNT);
+        for (int i = 0; i < pssProto.powerEntityInfo.length; i++) {
+            PowerEntityInfoProto powerEntityInfo = pssProto.powerEntityInfo[i];
+            assertTrue(powerEntityInfo.powerEntityId == i);
+            assertTrue(powerEntityInfo.powerEntityName.equals(POWER_ENTITY_NAME + i));
+            for (int j = 0; j < powerEntityInfo.states.length; j++) {
+                StateInfoProto stateInfo = powerEntityInfo.states[j];
+                assertTrue(stateInfo.stateId == j);
+                assertTrue(stateInfo.stateName.equals(STATE_NAME + j));
+            }
+        }
+
+        // No stateResidencyResults should be written to the incident report since it
+        // is all corrupt (random bytes generated above).
+        assertTrue(pssProto.stateResidencyResult.length == 0);
+    }
+
+    @Test
     public void testNotEnoughBytesAfterMeterLengthField() throws IOException {
         mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
 
@@ -467,4 +586,54 @@
         // input buffer had only length and no data.
         assertTrue(pssProto.energyConsumerResult.length == 0);
     }
+
+    @Test
+    public void testNotEnoughBytesAfterResidencyLengthField() throws IOException {
+        mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
+
+        // Create corrupt data.
+        // Length field is correct, but there is no data following the length.
+        ByteArrayOutputStream data = new ByteArrayOutputStream();
+        data.write(ByteBuffer.allocate(4).putInt(50).array());
+        byte[] test = data.toByteArray();
+
+        // Store corrupt data in on-device storage.  Add fake timestamp to filename
+        // to match format expected by FileRotator.
+        File onDeviceStorageFile = new File(mDataStorageDir, RESIDENCY_FILENAME + ".1234-2234");
+        FileOutputStream onDeviceStorageFos = new FileOutputStream(onDeviceStorageFile);
+        onDeviceStorageFos.write(data.toByteArray());
+        onDeviceStorageFos.close();
+
+        // Write on-device storage to an incident report.
+        File incidentReport = new File(mDataStorageDir, PROTO_OUTPUT_FILENAME);
+        FileOutputStream incidentReportFos = new FileOutputStream(incidentReport);
+        mPowerStatsLogger.writeResidencyDataToFile(incidentReportFos.getFD());
+
+        // Read the incident report in to a byte array.
+        FileInputStream fis = new FileInputStream(incidentReport);
+        byte[] fileContent = new byte[(int) incidentReport.length()];
+        fis.read(fileContent);
+
+        // Parse the incident data into a PowerStatsServiceResidencyProto object.
+        PowerStatsServiceResidencyProto pssProto =
+                PowerStatsServiceResidencyProto.parseFrom(fileContent);
+
+        // Valid powerEntityInfo data is written to the incident report in the call to
+        // mPowerStatsLogger.writeResidencyDataToFile().
+        assertTrue(pssProto.powerEntityInfo.length == POWER_ENTITY_COUNT);
+        for (int i = 0; i < pssProto.powerEntityInfo.length; i++) {
+            PowerEntityInfoProto powerEntityInfo = pssProto.powerEntityInfo[i];
+            assertTrue(powerEntityInfo.powerEntityId == i);
+            assertTrue(powerEntityInfo.powerEntityName.equals(POWER_ENTITY_NAME + i));
+            for (int j = 0; j < powerEntityInfo.states.length; j++) {
+                StateInfoProto stateInfo = powerEntityInfo.states[j];
+                assertTrue(stateInfo.stateId == j);
+                assertTrue(stateInfo.stateName.equals(STATE_NAME + j));
+            }
+        }
+
+        // No stateResidencyResults should be written to the incident report since the
+        // input buffer had only length and no data.
+        assertTrue(pssProto.stateResidencyResult.length == 0);
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index fee848b..e8045e0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -720,7 +720,6 @@
         }
         // caller is instrumenting with background activity starts privileges
         callerApp.setInstrumenting(callerIsInstrumentingWithBackgroundActivityStartPrivileges,
-                callerIsInstrumentingWithBackgroundActivityStartPrivileges ? Process.SHELL_UID : -1,
                 callerIsInstrumentingWithBackgroundActivityStartPrivileges);
         // callingUid is the device owner
         doReturn(isCallingUidDeviceOwner).when(mAtm).isDeviceOwner(callingUid);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
index 475e462..009c011 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
@@ -31,13 +31,17 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.timeout;
 
 import android.app.WaitResult;
+import android.content.ComponentName;
 import android.content.pm.ActivityInfo;
+import android.os.ConditionVariable;
 import android.platform.test.annotations.Presubmit;
 import android.view.Display;
 
@@ -58,6 +62,7 @@
 @Presubmit
 @RunWith(WindowTestRunner.class)
 public class ActivityTaskSupervisorTests extends WindowTestsBase {
+    private static final long TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10);
 
     /**
      * Ensures that an activity is removed from the stopping activities list once it is resumed.
@@ -74,30 +79,72 @@
     }
 
     /**
-     * Ensures that waiting results are notified of launches.
+     * Assume an activity has been started with result code START_SUCCESS. And before it is drawn,
+     * it launches another existing activity. This test ensures that waiting results are notified
+     * or updated while the result code of next launch is TASK_TO_FRONT or DELIVERED_TO_TOP.
      */
     @Test
-    public void testReportWaitingActivityLaunchedIfNeeded() {
+    public void testReportWaitingActivityLaunched() {
         final ActivityRecord firstActivity = new ActivityBuilder(mAtm)
                 .setCreateTask(true).build();
-
+        final ActivityRecord secondActivity = new ActivityBuilder(mAtm)
+                .setCreateTask(true).build();
+        final ConditionVariable condition = new ConditionVariable();
         final WaitResult taskToFrontWait = new WaitResult();
-        mSupervisor.mWaitingActivityLaunched.add(taskToFrontWait);
-        // #notifyAll will be called on the ActivityTaskManagerService#mGlobalLock. The lock is hold
-        // implicitly by WindowManagerGlobalLockRule.
-        mSupervisor.reportWaitingActivityLaunchedIfNeeded(firstActivity, START_TASK_TO_FRONT);
+        final ComponentName[] launchedComponent = { null };
+        // Create a new thread so the waiting method in test can be notified.
+        new Thread(() -> {
+            synchronized (mAtm.mGlobalLock) {
+                // Note that TASK_TO_FRONT doesn't unblock the waiting thread.
+                mSupervisor.reportWaitingActivityLaunchedIfNeeded(firstActivity,
+                        START_TASK_TO_FRONT);
+                launchedComponent[0] = taskToFrontWait.who;
+                // Assume that another task is brought to front because first activity launches it.
+                mSupervisor.reportActivityLaunched(false /* timeout */, secondActivity,
+                        100 /* totalTime */, WaitResult.LAUNCH_STATE_HOT);
+            }
+            condition.open();
+        }).start();
+        final ActivityMetricsLogger.LaunchingState launchingState =
+                new ActivityMetricsLogger.LaunchingState();
+        spyOn(launchingState);
+        doReturn(true).when(launchingState).contains(eq(secondActivity));
+        // The test case already runs inside global lock, so above thread can only execute after
+        // this waiting method that releases the lock.
+        mSupervisor.waitActivityVisibleOrLaunched(taskToFrontWait, firstActivity, launchingState);
 
-        assertThat(mSupervisor.mWaitingActivityLaunched).isEmpty();
+        // Assert that the thread is finished.
+        assertTrue(condition.block(TIMEOUT_MS));
         assertEquals(taskToFrontWait.result, START_TASK_TO_FRONT);
-        assertNull(taskToFrontWait.who);
+        assertEquals(taskToFrontWait.who, secondActivity.mActivityComponent);
+        assertEquals(taskToFrontWait.launchState, WaitResult.LAUNCH_STATE_HOT);
+        // START_TASK_TO_FRONT means that another component will be visible, so the component
+        // should not be assigned as the first activity.
+        assertNull(launchedComponent[0]);
 
+        condition.close();
         final WaitResult deliverToTopWait = new WaitResult();
-        mSupervisor.mWaitingActivityLaunched.add(deliverToTopWait);
-        mSupervisor.reportWaitingActivityLaunchedIfNeeded(firstActivity, START_DELIVERED_TO_TOP);
+        new Thread(() -> {
+            synchronized (mAtm.mGlobalLock) {
+                // Put a noise which isn't tracked by the current wait result. The waiting procedure
+                // should ignore it and keep waiting for the target activity.
+                mSupervisor.reportActivityLaunched(false /* timeout */, mock(ActivityRecord.class),
+                        1000 /* totalTime */, WaitResult.LAUNCH_STATE_COLD);
+                // Assume that the first activity launches an existing top activity, so the waiting
+                // thread should be unblocked.
+                mSupervisor.reportWaitingActivityLaunchedIfNeeded(secondActivity,
+                        START_DELIVERED_TO_TOP);
+            }
+            condition.open();
+        }).start();
+        mSupervisor.waitActivityVisibleOrLaunched(deliverToTopWait, firstActivity, launchingState);
 
-        assertThat(mSupervisor.mWaitingActivityLaunched).isEmpty();
+        assertTrue(condition.block(TIMEOUT_MS));
         assertEquals(deliverToTopWait.result, START_DELIVERED_TO_TOP);
-        assertEquals(deliverToTopWait.who, firstActivity.mActivityComponent);
+        assertEquals(deliverToTopWait.who, secondActivity.mActivityComponent);
+        // The result state must be unknown because DELIVERED_TO_TOP means that the target activity
+        // is already visible so there is no valid launch time.
+        assertEquals(deliverToTopWait.launchState, WaitResult.LAUNCH_STATE_UNKNOWN);
     }
 
     /**
@@ -202,7 +249,6 @@
     public void testStartHomeAfterUserUnlocked() {
         mSupervisor.onUserUnlocked(0);
         waitHandlerIdle(mAtm.mH);
-        verify(mRootWindowContainer, timeout(TimeUnit.SECONDS.toMillis(10)))
-                .startHomeOnEmptyDisplays("userUnlocked");
+        verify(mRootWindowContainer, timeout(TIMEOUT_MS)).startHomeOnEmptyDisplays("userUnlocked");
     }
 }
diff --git a/services/translation/Android.bp b/services/translation/Android.bp
new file mode 100644
index 0000000..804a617
--- /dev/null
+++ b/services/translation/Android.bp
@@ -0,0 +1,13 @@
+filegroup {
+    name: "services.translation-sources",
+    srcs: ["java/**/*.java"],
+    path: "java",
+    visibility: ["//frameworks/base/services"],
+}
+
+java_library_static {
+    name: "services.translation",
+    defaults: ["platform_service_defaults"],
+    srcs: [":services.translation-sources"],
+    libs: ["services.core"],
+}
\ No newline at end of file
diff --git a/services/translation/OWNERS b/services/translation/OWNERS
new file mode 100644
index 0000000..a1e663a
--- /dev/null
+++ b/services/translation/OWNERS
@@ -0,0 +1,8 @@
+# Bug component: 994311
+
+adamhe@google.com
+augale@google.com
+joannechung@google.com
+lpeter@google.com
+svetoslavganov@google.com
+tymtsai@google.com
diff --git a/services/translation/java/com/android/server/translation/RemoteTranslationService.java b/services/translation/java/com/android/server/translation/RemoteTranslationService.java
new file mode 100644
index 0000000..0c7e617
--- /dev/null
+++ b/services/translation/java/com/android/server/translation/RemoteTranslationService.java
@@ -0,0 +1,87 @@
+/*
+ * 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.translation;
+
+import android.annotation.NonNull;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.service.translation.ITranslationService;
+import android.service.translation.TranslationService;
+import android.util.Slog;
+import android.view.translation.TranslationSpec;
+
+import com.android.internal.infra.AbstractRemoteService;
+import com.android.internal.infra.ServiceConnector;
+import com.android.internal.os.IResultReceiver;
+
+final class RemoteTranslationService extends ServiceConnector.Impl<ITranslationService> {
+
+    private static final String TAG = RemoteTranslationService.class.getSimpleName();
+
+    // TODO(b/176590870): Make PERMANENT now.
+    private static final long TIMEOUT_IDLE_UNBIND_MS =
+            AbstractRemoteService.PERMANENT_BOUND_TIMEOUT_MS;
+    private static final int TIMEOUT_REQUEST_MS = 5_000;
+
+    private final long mIdleUnbindTimeoutMs;
+    private final int mRequestTimeoutMs;
+    private final ComponentName mComponentName;
+
+    RemoteTranslationService(Context context, ComponentName serviceName,
+            int userId, boolean bindInstantServiceAllowed) {
+        super(context,
+                new Intent(TranslationService.SERVICE_INTERFACE).setComponent(serviceName),
+                bindInstantServiceAllowed ? Context.BIND_ALLOW_INSTANT : 0,
+                userId, ITranslationService.Stub::asInterface);
+        mIdleUnbindTimeoutMs = TIMEOUT_IDLE_UNBIND_MS;
+        mRequestTimeoutMs = TIMEOUT_REQUEST_MS;
+        mComponentName = serviceName;
+
+        // Bind right away.
+        connect();
+    }
+
+    public ComponentName getComponentName() {
+        return mComponentName;
+    }
+
+    @Override // from ServiceConnector.Impl
+    protected void onServiceConnectionStatusChanged(ITranslationService service,
+            boolean connected) {
+        try {
+            if (connected) {
+                service.onConnected();
+            } else {
+                service.onDisconnected();
+            }
+        } catch (Exception e) {
+            Slog.w(TAG,
+                    "Exception calling onServiceConnectionStatusChanged(" + connected + "): ", e);
+        }
+    }
+
+    @Override // from AbstractRemoteService
+    protected long getAutoDisconnectTimeoutMs() {
+        return mIdleUnbindTimeoutMs;
+    }
+
+    public void onSessionCreated(@NonNull TranslationSpec sourceSpec,
+            @NonNull TranslationSpec destSpec, int sessionId, IResultReceiver resultReceiver) {
+        run((s) -> s.onCreateTranslationSession(sourceSpec, destSpec, sessionId, resultReceiver));
+    }
+}
diff --git a/services/translation/java/com/android/server/translation/TranslationManagerService.java b/services/translation/java/com/android/server/translation/TranslationManagerService.java
new file mode 100644
index 0000000..e2aabe6
--- /dev/null
+++ b/services/translation/java/com/android/server/translation/TranslationManagerService.java
@@ -0,0 +1,92 @@
+/*
+ * 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.translation;
+
+import static android.content.Context.TRANSLATION_MANAGER_SERVICE;
+import static android.view.translation.TranslationManager.STATUS_SYNC_CALL_FAIL;
+
+import android.content.Context;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.view.translation.ITranslationManager;
+import android.view.translation.TranslationSpec;
+
+import com.android.internal.os.IResultReceiver;
+import com.android.server.infra.AbstractMasterSystemService;
+import com.android.server.infra.FrameworkResourcesServiceNameResolver;
+
+/**
+ * Entry point service for translation management.
+ *
+ * <p>This service provides the {@link ITranslationManager} implementation and keeps a list of
+ * {@link TranslationManagerServiceImpl} per user; the real work is done by
+ * {@link TranslationManagerServiceImpl} itself.
+ */
+public final class TranslationManagerService
+        extends AbstractMasterSystemService<TranslationManagerService,
+        TranslationManagerServiceImpl> {
+
+    private static final String TAG = "TranslationManagerService";
+
+    public TranslationManagerService(Context context) {
+        // TODO: Discuss the disallow policy
+        super(context, new FrameworkResourcesServiceNameResolver(context,
+                        com.android.internal.R.string.config_defaultTranslationService),
+                /* disallowProperty */ null, PACKAGE_UPDATE_POLICY_REFRESH_EAGER);
+    }
+
+    @Override
+    protected TranslationManagerServiceImpl newServiceLocked(int resolvedUserId, boolean disabled) {
+        return new TranslationManagerServiceImpl(this, mLock, resolvedUserId, disabled);
+    }
+
+    final class TranslationManagerServiceStub extends ITranslationManager.Stub {
+        @Override
+        public void getSupportedLocales(IResultReceiver receiver, int userId)
+                throws RemoteException {
+            synchronized (mLock) {
+                final TranslationManagerServiceImpl service = getServiceForUserLocked(userId);
+                if (service != null) {
+                    service.getSupportedLocalesLocked(receiver);
+                } else {
+                    Slog.v(TAG, "getSupportedLocales(): no service for " + userId);
+                    receiver.send(STATUS_SYNC_CALL_FAIL, null);
+                }
+            }
+        }
+
+        @Override
+        public void onSessionCreated(TranslationSpec sourceSpec, TranslationSpec destSpec,
+                int sessionId, IResultReceiver receiver, int userId) throws RemoteException {
+            synchronized (mLock) {
+                final TranslationManagerServiceImpl service = getServiceForUserLocked(userId);
+                if (service != null) {
+                    service.onSessionCreatedLocked(sourceSpec, destSpec, sessionId, receiver);
+                } else {
+                    Slog.v(TAG, "onSessionCreated(): no service for " + userId);
+                    receiver.send(STATUS_SYNC_CALL_FAIL, null);
+                }
+            }
+        }
+    }
+
+    @Override // from SystemService
+    public void onStart() {
+        publishBinderService(TRANSLATION_MANAGER_SERVICE,
+                new TranslationManagerService.TranslationManagerServiceStub());
+    }
+}
diff --git a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
new file mode 100644
index 0000000..b1f6f80
--- /dev/null
+++ b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
@@ -0,0 +1,125 @@
+/*
+ * 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.translation;
+
+import static android.view.translation.TranslationManager.STATUS_SYNC_CALL_SUCCESS;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.os.RemoteException;
+import android.service.translation.TranslationServiceInfo;
+import android.util.Slog;
+import android.view.translation.TranslationSpec;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.IResultReceiver;
+import com.android.internal.util.SyncResultReceiver;
+import com.android.server.infra.AbstractPerUserSystemService;
+
+import java.util.ArrayList;
+
+final class TranslationManagerServiceImpl extends
+        AbstractPerUserSystemService<TranslationManagerServiceImpl, TranslationManagerService> {
+
+    private static final String TAG = "TranslationManagerServiceImpl";
+
+    @GuardedBy("mLock")
+    @Nullable
+    private RemoteTranslationService mRemoteTranslationService;
+
+    @GuardedBy("mLock")
+    @Nullable
+    private ServiceInfo mRemoteTranslationServiceInfo;
+
+    protected TranslationManagerServiceImpl(
+            @NonNull TranslationManagerService master,
+            @NonNull Object lock, int userId, boolean disabled) {
+        super(master, lock, userId);
+        updateRemoteServiceLocked();
+    }
+
+    @GuardedBy("mLock")
+    @Override // from PerUserSystemService
+    protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent)
+            throws PackageManager.NameNotFoundException {
+        final TranslationServiceInfo info = new TranslationServiceInfo(getContext(),
+                serviceComponent, isTemporaryServiceSetLocked(), mUserId);
+        mRemoteTranslationServiceInfo = info.getServiceInfo();
+        return info.getServiceInfo();
+    }
+
+    @GuardedBy("mLock")
+    @Override // from PerUserSystemService
+    protected boolean updateLocked(boolean disabled) {
+        final boolean enabledChanged = super.updateLocked(disabled);
+        updateRemoteServiceLocked();
+        return enabledChanged;
+    }
+
+    /**
+     * Updates the reference to the remote service.
+     */
+    @GuardedBy("mLock")
+    private void updateRemoteServiceLocked() {
+        if (mRemoteTranslationService != null) {
+            if (mMaster.debug) Slog.d(TAG, "updateRemoteService(): destroying old remote service");
+            mRemoteTranslationService.unbind();
+            mRemoteTranslationService = null;
+        }
+    }
+
+    @GuardedBy("mLock")
+    @Nullable
+    private RemoteTranslationService ensureRemoteServiceLocked() {
+        if (mRemoteTranslationService == null) {
+            final String serviceName = getComponentNameLocked();
+            if (serviceName == null) {
+                if (mMaster.verbose) {
+                    Slog.v(TAG, "ensureRemoteServiceLocked(): no service component name.");
+                }
+                return null;
+            }
+            final ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName);
+            mRemoteTranslationService = new RemoteTranslationService(getContext(),
+                    serviceComponent, mUserId, /* isInstantAllowed= */ false);
+        }
+        return mRemoteTranslationService;
+    }
+
+    @GuardedBy("mLock")
+    void getSupportedLocalesLocked(@NonNull IResultReceiver resultReceiver) {
+        // TODO: implement this
+        try {
+            resultReceiver.send(STATUS_SYNC_CALL_SUCCESS,
+                    SyncResultReceiver.bundleFor(new ArrayList<>()));
+        } catch (RemoteException e) {
+            Slog.w(TAG, "RemoteException returning supported locales: " + e);
+        }
+    }
+
+    @GuardedBy("mLock")
+    void onSessionCreatedLocked(@NonNull TranslationSpec sourceSpec,
+            @NonNull TranslationSpec destSpec, int sessionId, IResultReceiver resultReceiver) {
+        final RemoteTranslationService remoteService = ensureRemoteServiceLocked();
+        if (remoteService != null) {
+            remoteService.onSessionCreated(sourceSpec, destSpec, sessionId, resultReceiver);
+        }
+    }
+}
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index a762219..f6a2846 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -70,4 +70,7 @@
         "android.test.base",
         "android.test.mock",
     ],
+    jni_libs: [
+        "libservice-connectivity",
+    ],
 }
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 3433880..e318207 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -1199,6 +1199,8 @@
                 updateState(NetworkInfo.DetailedState.DISCONNECTED, "disconnect");
             }
             mAgentRegistered = false;
+            setUids(null);
+            mInterface = null;
         }
 
         @Override
@@ -3624,51 +3626,55 @@
         // Register the factory and expect it to start looking for a network.
         testFactory.expectAddRequestsWithScores(0);  // Score 0 as the request is not served yet.
         testFactory.register();
-        testFactory.waitForNetworkRequests(1);
-        assertTrue(testFactory.getMyStartRequested());
 
-        // Bring up wifi. The factory stops looking for a network.
-        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-        // Score 60 - 40 penalty for not validated yet, then 60 when it validates
-        testFactory.expectAddRequestsWithScores(20, 60);
-        mWiFiNetworkAgent.connect(true);
-        testFactory.waitForRequests();
-        assertFalse(testFactory.getMyStartRequested());
+        try {
+            testFactory.waitForNetworkRequests(1);
+            assertTrue(testFactory.getMyStartRequested());
 
-        ContentResolver cr = mServiceContext.getContentResolver();
+            // Bring up wifi. The factory stops looking for a network.
+            mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+            // Score 60 - 40 penalty for not validated yet, then 60 when it validates
+            testFactory.expectAddRequestsWithScores(20, 60);
+            mWiFiNetworkAgent.connect(true);
+            testFactory.waitForRequests();
+            assertFalse(testFactory.getMyStartRequested());
 
-        // Turn on mobile data always on. The factory starts looking again.
-        testFactory.expectAddRequestsWithScores(0);  // Always on requests comes up with score 0
-        setAlwaysOnNetworks(true);
-        testFactory.waitForNetworkRequests(2);
-        assertTrue(testFactory.getMyStartRequested());
+            ContentResolver cr = mServiceContext.getContentResolver();
 
-        // Bring up cell data and check that the factory stops looking.
-        assertLength(1, mCm.getAllNetworks());
-        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
-        testFactory.expectAddRequestsWithScores(10, 50);  // Unvalidated, then validated
-        mCellNetworkAgent.connect(true);
-        cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-        testFactory.waitForNetworkRequests(2);
-        assertFalse(testFactory.getMyStartRequested());  // Because the cell network outscores us.
+            // Turn on mobile data always on. The factory starts looking again.
+            testFactory.expectAddRequestsWithScores(0);  // Always on requests comes up with score 0
+            setAlwaysOnNetworks(true);
+            testFactory.waitForNetworkRequests(2);
+            assertTrue(testFactory.getMyStartRequested());
 
-        // Check that cell data stays up.
-        waitForIdle();
-        verifyActiveNetwork(TRANSPORT_WIFI);
-        assertLength(2, mCm.getAllNetworks());
+            // Bring up cell data and check that the factory stops looking.
+            assertLength(1, mCm.getAllNetworks());
+            mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+            testFactory.expectAddRequestsWithScores(10, 50);  // Unvalidated, then validated
+            mCellNetworkAgent.connect(true);
+            cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+            testFactory.waitForNetworkRequests(2);
+            assertFalse(
+                    testFactory.getMyStartRequested());  // Because the cell network outscores us.
 
-        // Turn off mobile data always on and expect the request to disappear...
-        testFactory.expectRemoveRequests(1);
-        setAlwaysOnNetworks(false);
-        testFactory.waitForNetworkRequests(1);
+            // Check that cell data stays up.
+            waitForIdle();
+            verifyActiveNetwork(TRANSPORT_WIFI);
+            assertLength(2, mCm.getAllNetworks());
 
-        // ...  and cell data to be torn down.
-        cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
-        assertLength(1, mCm.getAllNetworks());
+            // Turn off mobile data always on and expect the request to disappear...
+            testFactory.expectRemoveRequests(1);
+            setAlwaysOnNetworks(false);
+            testFactory.waitForNetworkRequests(1);
 
-        testFactory.terminate();
-        mCm.unregisterNetworkCallback(cellNetworkCallback);
-        handlerThread.quit();
+            // ...  and cell data to be torn down.
+            cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+            assertLength(1, mCm.getAllNetworks());
+        } finally {
+            testFactory.terminate();
+            mCm.unregisterNetworkCallback(cellNetworkCallback);
+            handlerThread.quit();
+        }
     }
 
     @Test
@@ -6176,11 +6182,15 @@
 
         // Create a fake restricted profile whose parent is our user ID.
         final int userId = UserHandle.getUserId(uid);
+        when(mUserManager.canHaveRestrictedProfile(userId)).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));
+
         final Intent addedIntent = new Intent(ACTION_USER_ADDED);
         addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, restrictedUserId);
 
@@ -6220,6 +6230,54 @@
                 && caps.getUids().contains(new UidRange(uid, uid))
                 && caps.hasTransport(TRANSPORT_VPN)
                 && !caps.hasTransport(TRANSPORT_WIFI));
+
+        // Test lockdown with restricted profiles.
+        mServiceContext.setPermission(
+                Manifest.permission.CONTROL_ALWAYS_ON_VPN, PERMISSION_GRANTED);
+        mServiceContext.setPermission(
+                Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED);
+        mServiceContext.setPermission(
+                Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+
+        // 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 */);
+        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);
+        waitForIdle();
+        assertNull(mCm.getActiveNetworkForUid(uid));
+        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
+                }));
+        // TODO: check that VPN app within restricted profile still has access, etc.
+        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),
+                }));
+        handler.post(() -> mServiceContext.sendBroadcast(removedIntent));
+        waitForIdle();
+        assertNull(mCm.getActiveNetworkForUid(uid));
+        assertNotNull(mCm.getActiveNetworkForUid(restrictedUid));
+
+        mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
+        waitForIdle();
     }
 
     @Test
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 3648c4d..02a2aad 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -339,14 +339,8 @@
         final Vpn vpn = createVpn(primaryUser.id);
         final UidRange user = PRI_USER_RANGE;
 
-        // Default state.
-        assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1],
-                user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
-
         // Set always-on without lockdown.
         assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null, mKeyStore));
-        assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1],
-                user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
 
         // Set always-on with lockdown.
         assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null, mKeyStore));
@@ -355,10 +349,6 @@
                 new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop)
         }));
 
-        assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2],
-                user.start + PKG_UIDS[3]);
-        assertUnblocked(vpn, user.start + PKG_UIDS[1]);
-
         // Switch to another app.
         assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null, mKeyStore));
         verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
@@ -369,9 +359,6 @@
                 new UidRangeParcel(user.start, user.start + PKG_UIDS[3] - 1),
                 new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop)
         }));
-        assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1],
-                user.start + PKG_UIDS[2]);
-        assertUnblocked(vpn, user.start + PKG_UIDS[3]);
     }
 
     @Test
@@ -386,8 +373,6 @@
                 new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1),
                 new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop)
         }));
-        assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]);
-        assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
         // Change allowed app list to PKGS[3].
         assertTrue(vpn.setAlwaysOnPackage(
                 PKGS[1], true, Collections.singletonList(PKGS[3]), mKeyStore));
@@ -398,8 +383,6 @@
                 new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1),
                 new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop)
         }));
-        assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2]);
-        assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[3]);
 
         // Change the VPN app.
         assertTrue(vpn.setAlwaysOnPackage(
@@ -412,8 +395,6 @@
                 new UidRangeParcel(user.start, user.start + PKG_UIDS[0] - 1),
                 new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1)
         }));
-        assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
-        assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]);
 
         // Remove the list of allowed packages.
         assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null, mKeyStore));
@@ -424,9 +405,6 @@
         verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
                 new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.stop),
         }));
-        assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2],
-                user.start + PKG_UIDS[3]);
-        assertUnblocked(vpn, user.start + PKG_UIDS[0]);
 
         // Add the list of allowed packages.
         assertTrue(vpn.setAlwaysOnPackage(
@@ -438,8 +416,6 @@
                 new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
                 new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop)
         }));
-        assertBlocked(vpn, user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
-        assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1]);
 
         // Try allowing a package with a comma, should be rejected.
         assertFalse(vpn.setAlwaysOnPackage(
@@ -460,45 +436,6 @@
     }
 
     @Test
-    public void testLockdownAddingAProfile() throws Exception {
-        final Vpn vpn = createVpn(primaryUser.id);
-        setMockedUsers(primaryUser);
-
-        // Make a copy of the restricted profile, as we're going to mark it deleted halfway through.
-        final UserInfo tempProfile = new UserInfo(restrictedProfileA.id, restrictedProfileA.name,
-                restrictedProfileA.flags);
-        tempProfile.restrictedProfileParentId = primaryUser.id;
-
-        final UidRange user = PRI_USER_RANGE;
-        final UidRange profile = UidRange.createForUser(tempProfile.id);
-
-        // Set lockdown.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null, mKeyStore));
-        verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
-                new UidRangeParcel(user.start, user.start + PKG_UIDS[3] - 1),
-                new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop)
-        }));
-        // Verify restricted user isn't affected at first.
-        assertUnblocked(vpn, profile.start + PKG_UIDS[0]);
-
-        // Add the restricted user.
-        setMockedUsers(primaryUser, tempProfile);
-        vpn.onUserAdded(tempProfile.id);
-        verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
-                new UidRangeParcel(profile.start, profile.start + PKG_UIDS[3] - 1),
-                new UidRangeParcel(profile.start + PKG_UIDS[3] + 1, profile.stop)
-        }));
-
-        // Remove the restricted user.
-        tempProfile.partial = true;
-        vpn.onUserRemoved(tempProfile.id);
-        verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
-                new UidRangeParcel(profile.start, profile.start + PKG_UIDS[3] - 1),
-                new UidRangeParcel(profile.start + PKG_UIDS[3] + 1, profile.stop)
-        }));
-    }
-
-    @Test
     public void testLockdownRuleRepeatability() throws Exception {
         final Vpn vpn = createVpn(primaryUser.id);
         final UidRangeParcel[] primaryUserRangeParcel = new UidRangeParcel[] {
@@ -1207,20 +1144,6 @@
         return vpn;
     }
 
-    private static void assertBlocked(Vpn vpn, int... uids) {
-        for (int uid : uids) {
-            final boolean blocked = vpn.getLockdown() && vpn.isBlockingUid(uid);
-            assertTrue("Uid " + uid + " should be blocked", blocked);
-        }
-    }
-
-    private static void assertUnblocked(Vpn vpn, int... uids) {
-        for (int uid : uids) {
-            final boolean blocked = vpn.getLockdown() && vpn.isBlockingUid(uid);
-            assertFalse("Uid " + uid + " should not be blocked", blocked);
-        }
-    }
-
     /**
      * Populate {@link #mUserManager} with a list of fake users.
      */
diff --git a/tools/powerstats/PowerStatsServiceProtoParser.java b/tools/powerstats/PowerStatsServiceProtoParser.java
index 76edd63..97a2a40 100644
--- a/tools/powerstats/PowerStatsServiceProtoParser.java
+++ b/tools/powerstats/PowerStatsServiceProtoParser.java
@@ -90,6 +90,38 @@
         }
     }
 
+    private static void printPowerEntityInfo(PowerStatsServiceResidencyProto proto) {
+        String csvHeader = new String();
+        for (int i = 0; i < proto.getPowerEntityInfoCount(); i++) {
+            PowerEntityInfoProto powerEntityInfo = proto.getPowerEntityInfo(i);
+            csvHeader += powerEntityInfo.getPowerEntityId() + ","
+                + powerEntityInfo.getPowerEntityName() + ",";
+            for (int j = 0; j < powerEntityInfo.getStatesCount(); j++) {
+                StateInfoProto stateInfo = powerEntityInfo.getStates(j);
+                csvHeader += stateInfo.getStateId() + "," + stateInfo.getStateName() + ",";
+            }
+        }
+        System.out.println(csvHeader);
+    }
+
+    private static void printStateResidencyResult(PowerStatsServiceResidencyProto proto) {
+        for (int i = 0; i < proto.getStateResidencyResultCount(); i++) {
+            String csvRow = new String();
+
+            StateResidencyResultProto stateResidencyResult = proto.getStateResidencyResult(i);
+            csvRow += stateResidencyResult.getPowerEntityId() + ",";
+
+            for (int j = 0; j < stateResidencyResult.getStateResidencyDataCount(); j++) {
+                StateResidencyProto stateResidency = stateResidencyResult.getStateResidencyData(j);
+                csvRow += stateResidency.getStateId() + ","
+                    + stateResidency.getTotalTimeInStateMs() + ","
+                    + stateResidency.getTotalStateEntryCount() + ","
+                    + stateResidency.getLastEntryTimestampMs() + ",";
+            }
+            System.out.println(csvRow);
+        }
+    }
+
     private static void generateCsvFile(String pathToIncidentReport) {
         try {
             // Print power meter data.
@@ -115,6 +147,21 @@
             } else {
                 System.out.println("Model incident report not found.  Exiting.");
             }
+
+            // Print state residency data.
+            IncidentReportResidencyProto irResidencyProto =
+                    IncidentReportResidencyProto.parseFrom(
+                        new FileInputStream(pathToIncidentReport));
+
+            if (irResidencyProto.hasIncidentReport()) {
+                PowerStatsServiceResidencyProto pssResidencyProto =
+                        irResidencyProto.getIncidentReport();
+                printPowerEntityInfo(pssResidencyProto);
+                printStateResidencyResult(pssResidencyProto);
+            } else {
+                System.out.println("Residency incident report not found.  Exiting.");
+            }
+
         } catch (IOException e) {
             System.out.println("Unable to open incident report file: " + pathToIncidentReport);
             System.out.println(e);