Merge "Check updatable font dir in FontListParser."
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..32134fc 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -7135,7 +7135,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 +7186,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 +7492,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 +7827,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 +10362,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
@@ -48717,6 +48765,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);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 9a15e77..473a280 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -906,6 +906,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 +1371,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);
@@ -8618,6 +8617,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";
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..7bdcbc1 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -306,7 +306,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 +604,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 +667,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 +683,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 +713,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 +1192,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 +1257,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 +1385,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 +2471,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 +2529,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 +2571,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";
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..43011fc 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;
@@ -4821,6 +4822,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 +5312,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/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/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/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/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/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/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/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..3053518 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -5317,6 +5317,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/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..31b4edd 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" />
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/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/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/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/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/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/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/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/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index b46751d..b0bb3fd 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -40,6 +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.TaskViewFactory;
+import com.android.wm.shell.TaskViewFactoryController;
 import com.android.wm.shell.Transitions;
 import com.android.wm.shell.WindowManagerShellWrapper;
 import com.android.wm.shell.apppairs.AppPairs;
@@ -60,6 +62,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 +71,8 @@
 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 java.util.Optional;
-import java.util.concurrent.TimeUnit;
 
 import dagger.BindsOptionalOf;
 import dagger.Module;
@@ -342,6 +343,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/services/Android.bp b/services/Android.bp
index 3447b5c..b51e4b0 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -81,7 +81,6 @@
         "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/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/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/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/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/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/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..9088d7b 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -2078,7 +2078,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/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/Task.java b/services/core/java/com/android/server/wm/Task.java
index 1c41978..61410f8 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 */);
+        }
     }
 
     /**
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/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index fdbd85a..3e51b75 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -8421,7 +8421,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 +9734,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()) {
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/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/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/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/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/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);